Trying to catch MsgBox text and press button in xlwings - macros

So I have some code which uses xlwings for writing data in Excel file, xlsm.
after i've done writing, I press a certain button to calculate.
sometimes, an error/message pops in the Excel, which is fine, but i want to catch this message to python, and write it later to a log/print it.
also, i need to interact with this message, in this case to press "Ok" in the message box
Attached image of the message box

So guys, I've been able to solve this with an external python library.
here is the code:
from pywinauto import application as autoWin
app = autoWin.Application()
con = app.connect(title = 'Configuration Error')
msgText = con.Dialog.Static2.texts()[0]
con.Dialog.Button.click()
con.Dialog.Button.click()
print(msgText)
basically, what it does, is connecting to the app, and searching for the title.
in this case "Configuration Error"
it needs to perform double click in order to press "Ok" to close the message.
Secondly, it gets the text from the message, and can forward it wherever i want.
important part to remember though, because this should be an automated task, it should run concurrently, which means Threading.
so, a simple Thread class below:
class ButtonClicker(Thread):
def __init__(self):
Thread.__init__(self)
self._stop_event = Event()
def stop(self):
self._stop_event.set()
def stopped(self):
return self._stop_event.is_set()
def run(self) -> None:
while True:
time.sleep(3)
try:
app = autoWin.Application()
con = app.connect(title='Configuration Error')
msg_data = con.Dialog.Static2.texts()[0]
while True:
con.Dialog.Button.click()
# con.Dialog.Button.click()
# print(msg_data)
return msg_data
except Exception as e:
print('Excel didnt stuck')
break
and of course to actually use it:
event_handle = ButtonClicker()
event_handle.start()
some manipulation is needed in order to work in different codes/scenarios, but at least I hope i will help others in the future, because this seems to be very common question.

#Danny's solution, i.e. pywinauto and Thread, works perfectly in my local machine, but it seems can't catch the message box when Excel is running in server mode, e.g. in my case, the automation is triggered in local and started by a system service installed in the server.
pywinauto.findwindows.ElementNotFoundError:
{'title': '<my-wanted-title>', 'backend': 'win32', 'visible_only': False}
It is finally solved with another python third-party library pywin32, so providing a backup solution here.
'''
Keep finding message box with specified title and clicking button to close it,
until stopped by the main thread.
'''
import time
from threading import Thread, Event
import win32gui
import win32con
class ButtonClicker(Thread):
def __init__(self, title:str, interval:int):
Thread.__init__(self)
self._title = title
self._interval = interval
self._stop_event = Event()
def stop(self):
'''Stop thread.'''
self._stop_event.set()
#property
def stopped(self):
return self._stop_event.is_set()
def run(self):
while not self.stopped:
try:
time.sleep(self._interval)
self._close_msgbox()
except Exception as e:
print(e, flush=True)
def _close_msgbox(self):
# find the top window by title
hwnd = win32gui.FindWindow(None, self._title)
if not hwnd: return
# find child button
h_btn = win32gui.FindWindowEx(hwnd, None,'Button', None)
if not h_btn: return
# show text
text = win32gui.GetWindowText(h_btn)
print(text)
# click button
win32gui.PostMessage(h_btn, win32con.WM_LBUTTONDOWN, None, None)
time.sleep(0.2)
win32gui.PostMessage(h_btn, win32con.WM_LBUTTONUP, None, None)
time.sleep(0.2)
if __name__=='__main__':
t = ButtonClicker('Configuration Error', 3)
t.start()
time.sleep(10)
t.stop()

Related

Receiving signals from a PureScript Flame application

I'm experimenting to understand PureScript channels and signals better, and specifically their use with the UI library Flame.
I've created the following as a small example:
module Main where
import Prelude
import Effect (Effect)
import Flame (Html, QuerySelector(..))
import Flame.Application.NoEffects as FAN
import Flame.HTML.Attribute as HA
import Flame.HTML.Element as HE
data Message
= ButtonOne
| ButtonTwo
type Model
= { buttonOneCount :: Int
, buttonTwoCount :: Int
}
init :: Model
init =
{ buttonOneCount: 0
, buttonTwoCount: 0
}
update :: Model -> Message -> Model
update model message = case message of
ButtonOne -> model { buttonOneCount = model.buttonOneCount + 1 }
ButtonTwo -> model { buttonTwoCount = model.buttonTwoCount + 1 }
view :: Model -> Html Message
view model =
HE.main "main"
[ HE.button [ HA.onClick ButtonOne ] "Button One"
, HE.p_ ("button one: " <> show model.buttonOneCount)
, HE.button [ HA.onClick ButtonTwo ] "Button Two"
, HE.p_ ("button two: " <> show model.buttonTwoCount)
]
main :: Effect Unit
main = do
-- flameChannel :: Channel (Array Message)
flameChannel <-
FAN.mount (QuerySelector "main")
{ init, update, view }
pure unit
I'm aware that any changes should be handled in update here, but as an experiment I'd like to subscribe to changes to flameChannel in main and run some code based on the Message Flame sends through that channel.
Just to get started, what could be added to make this output to the JavaScript console when the user clicks Button One or Button Two, using flameChannel in main?
I've tried playing around with various combinations of functions from purescript-signal: subscribe, runSignal, get, but got nowhere. I have also looked around at various games on GitHub that use the purescript-signal library, but they just seem to throw runSignal into the code, everything works and I don't understand why (also, those examples are a bit complex and far from what I'm trying to do).
ok let's see - as you've already noticed you get a Channel (from signal) back that will notify you about Messages
you should now be able to use Signal.Channel.subscribe to turn this into a Signal
Now the way Signal works is that you should provide a Signal signaling Effects (those will be executed/run) to runSignal - so you have to turn your Signal (Array Message) into a Signal (Effect Unit) first.
Luckily Signal is a Functor so you can use map or the provided ~> (flipped map) to do this. I would suggest using flattenArray first to make your life a bit easier:
logMessage :: Message -> Effect Unit
logMessage msg =
case msg of
ButtonOne -> log "button one"
ButtonTwo -> log "button two"
and in main:
main = do
flameChannel <-
FAN.mount (QuerySelector "main")
{ init, update, view }
let logSignal =
map logMessage $ flip flattenArray ButtonOne $ subscribe flameChannel
runSignal logSignal
this should work
disclaimer: I did not try to compile this - if you get any issues please report and I'll see to it

How to save edited webview result?

Situation description:
Python 3.7, GTK 3.0, PyGObjects 3.34.0 Webkit2 4.0
I have a dialog window, with GtkNotebook containing 2 tabs.
1. tab contains editable Webkit webview, the 2. tab contains textview. One of the arguments provided in class consrtructor is valid HTML snippet as string variable
What I would like to get as a result, is that any changes made in any window, are automatically reflected in other.
Current problem:
Using solution provided here, any previous changes that were made in webview are discarded upon switching the notepad tabs. Debugging shows that html obtained with aforementioned call, does not contain changes.
Any ideas what might be missing in the logic or handling itself?
For reference, the code for the dialog is as follows:
# -*- coding: utf-8 -*-
import gi
gi.require_version('Gtk', '3.0')
gi.require_version('WebKit2', '4.0')
from gi.repository import Gtk, WebKit2
class DescriptionDialog:
def __init__(self, *args):
# GTK Builder
self._builder = args[0]
self._builder.add_from_file("UI/GUI/description.glade")
self.dialog = self._builder.get_object("descriptionDialog")
self._textView = self._builder.get_object("textview1")
self.webViewContainer = self._builder.get_object("WebViewContainer")
self.browserHolder = WebKit2.WebView()
self.browserHolder.set_editable(True)
self.webViewContainer.add(self.browserHolder)
self.browserHolder.show()
# valid html snippet, held as string
self.__buffer_orig__ = args[2]
self.buffer = args[2]
self.browserHolder.load_html(self.buffer)
self._builder.connect_signals(
{
"onDialogClose": self.onDialogClose,
"pageChangeNotebook": self.onPageChange
})
self.dialog.set_transient_for(self._builder.get_object("MainWindow"))
self.textBuffer = self._builder.get_object("textbuffer1")
self.textBuffer.set_text(self.buffer)
self.dialog.show()
def onDialogClose(self, handler):
self.dialog.hide()
def onPageChange(self, notebook=None, scrolledWindow=None, pageNumber=0):
if pageNumber == 0:
self.buffer = self.textBuffer.get_text(self.textBuffer.get_start_iter(), self.textBuffer.get_end_iter(), True)
self.browserHolder.load_html(self.buffer)
if pageNumber == 1:
self.browserHolder.get_main_resource().get_data(None, self.getDataFromResource, None)
def getDataFromResource(self, resource, result, userData=None):
# Changed html is not returned here
self.buffer = str(resource.get_data_finish(result).decode("utf-8"))
self.textBuffer.set_text(self.buffer)
For other internet users finding this thread.
Currently, at the given versions, this is the working result that I have come up with.
Main idea with this implementation is following - use the WebView enabled Javascript engine to obtain the contents of a <body> tag. Then, parse the Javascript result to use this value later on.
def onPageChange(self, notebook=None, scrolledWindow=None, pageNumber=0):
if pageNumber == 0:
self.buffer = self.textBuffer.get_text(self.textBuffer.get_start_iter(), self.textBuffer.get_end_iter(), True)
self.browserHolder.load_html(self.buffer)
if pageNumber == 1:
# use JavaScript to get the html contained in rendered body tag
script = "document.body.innerHTML;"
# Execute JavasScript via WebKit2.WebView bindings.
# Result can be obtained asynchronously, via callback method
self.browserHolder.run_javascript(script, None, self.getJSStatus, None)
def getJSStatus(self, resource, result, userData=None):
# Sample adapted and simplified from here:
# https://lazka.github.io/pgi-docs/#WebKit2-4.0/classes/WebView.html#WebKit2.WebView.run_javascript_finish
# Get the JavaScript result
data = self.browserHolder.run_javascript_finish(result)
# Get value from result, and convert it to string
self.buffer = data.get_js_value().to_string()
self.textBuffer.set_text(self.buffer)

How do I work with a Scala process interactively?

I'm writing a bot in Scala for a game that uses text input and output. So I want to work with a process interactively - that is, my code receives output from the process, works with it, and only then sends its next input to the process. So I want to give a function access to the inputStreams and the outputStream simultaneously.
This doesn't seem to fit into any of the factories in scala.sys.process.BasicIO or the constructor for scala.sys.process.ProcessIO (three functions, each of which has access to only one stream).
Here's how I'm doing it at the moment.
private var rogue_input: OutputStream = _
private var rogue_output: InputStream = _
private var rogue_error: InputStream = _
Process("python3 /home/robin/IdeaProjects/Rogomatic/python/rogue.py --rogomatic").run(
new ProcessIO(rogue_input = _, rogue_output = _, rogue_error = _)
)
try {
private val rogue_scanner = new Scanner(rogue_output)
private val rogue_writer = new PrintWriter(rogue_input, true)
// Play the game
} finally {
rogue_input.close()
rogue_output.close()
rogue_error.close()
}
This works, but it doesn't feel very Scala-like. Is there a more idiomatic way to do this?
So I want to work with a process interactively - that is, my code receives output from the process, works with it, and only then sends its next input to the process.
In general, this is traditionally solved by expect. There exist libraries and tools inspired by expect for various languages, including for Scala: https://github.com/Lasering/scala-expect.
The README of the project gives various examples. While I don't know exactly what your rouge.py expects in terms of stdin/stdout interactions, here's a quick "hello world" example showing how you could interact with a Python interpreter (using the Ammonite REPL, which has conveniently library importing capabilities):
import $ivy.`work.martins.simon::scala-expect:6.0.0`
import work.martins.simon.expect.core._
import work.martins.simon.expect.core.actions._
import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent.duration._
val timeout = 5 seconds
val e = new Expect("python3 -i -", defaultValue = "?")(
new ExpectBlock(
new StringWhen(">>> ")(
Sendln("""print("hello, world")""")
)
),
new ExpectBlock(
new RegexWhen("""(.*)\n>>> """.r)(
ReturningWithRegex(_.group(1).toString)
)
)
)
e.run(timeout).onComplete(println)
What the code above does is it "expects" >>> to be sent to stdout, and when it finds that, it will send print("hello, world"), followed by a newline. From then, it reads and returns everything until the next prompt (>>>) using a regex.
Amongst other debug information, the above should result in Success(hello, world) being printed to your console.
The library has various other styles, and there may also exist other similar libraries out there. My main point is that an expect-inspired library is likely what you're looking for.

Passing variables between classes in Tkinter, Python 3

I'm kind of a newbie to Python, and I'm writing some code to take data via a user input and put it into a .csv file. To do that, the program needs to pass data from class to class.
To teach myself how to pass data, I took code from here. I did have to alter the code a bit to get it to start up, making sure that the make_widget and print_it functions can pull the "name" variable stored in self.app_data data structure properly.
from tkinter import *
from tkinter import ttk
class MyApp(Tk):
def __init__(self):
Tk.__init__(self)
self.app_data={'name': StringVar}
container = ttk.Frame(self)
container.pack(side="top", fill="both", expand = True)
self.frames = {}
for F in (PageOne, PageTwo):
frame = F(container, self)
self.frames[F] = frame
frame.grid(row=0, column=0, sticky = NSEW)
self.show_frame(PageOne)
def show_frame(self, cont):
frame = self.frames[cont]
frame.tkraise()
class PageOne(ttk.Frame):
def __init__(self, parent, controller):
ttk.Frame.__init__(self, parent)
self.controller=controller
ttk.Label(self, text='PageOne').grid(padx=(20,20), pady=(20,20))
self.make_widget(controller)
def make_widget(self, controller):
self.controller=controller
self.some_entry = ttk.Entry(self, textvariable=self.controller.app_data['name'], width=8)
self.some_entry.grid()
button1 = ttk.Button(self, text='Next Page',command=lambda: controller.show_frame(PageTwo))
button1.grid()
class PageTwo(ttk.Frame):
def __init__(self, parent, controller):
ttk.Frame.__init__(self, parent)
self.controller=controller
ttk.Label(self, text='PageTwo').grid(padx=(20,20), pady=(20,20))
button1 = ttk.Button(self, text='Previous Page',command=lambda: controller.show_frame(PageOne))
button1.grid()
button2 = ttk.Button(self, text='press to print', command= self.print_it())
button2.grid()
def print_it(self):
value=self.controller.app_data['name'].get()
print ('The value stored in StartPage some_entry = ', value)#What do I put here
#to print the value of some_input from PageOne
When I run this program, it does start up, and I can move from frame to frame, but it does not print the "name" variable.
When I close the window, I get the error:
TypeError: get() missing 1 required positional argument: 'self'
Which the traceback blames on the line:
value=self.controller.app_data['name'].get()
What am I doing wrong? For what it's worth, I'm writing the code in Python 3.5.
I really appreciate any help that you guys could give me.

Call script through subproce.Popen without blocking explanation needed

Basically this code reads from a pipe and constantly prints output without blocking ... Here is the whole code:
1)First script:
if __name__ == '__main__':
for i in range(5):
print str(i)+'\n',
sys.stdout.flush()
time.sleep(1)
2) Second script:
def log_worker(stdout):
while True:
output = non_block_read(stdout).strip()
if output:
print output
def non_block_read(output):
''' even in a thread, a normal read with block until the buffer is full '''
fd = output.fileno()
fl = fcntl.fcntl(fd, fcntl.F_GETFL)
fcntl.fcntl(fd, fcntl.F_SETFL, fl | os.O_NONBLOCK)
try:
return output.read()
except:
return ''
if __name__ == '__main__':
mysql_process = subprocess.Popen(['python','-u', 'flush.py'], stdin=sys.stdin,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE)
thread = Thread(target=log_worker, args=[mysql_process.stdout])
thread.daemon = True
thread.start()
mysql_process.wait()
thread.join(timeout=1)
I would like to know why it works that way :
1) If i take Thread absolutely away , and just call log_worker in the main at also prints everything one by one , but the problem is it hangs after completion without finishing. And i read somewhere that here thread is exactly used for it to finish or more correctly thread dies when it finishes printing something , So why does it work that way ? What thread exactly does here and how ?
2) If i keep the thread but remove mysql_process.wait() and thread.join it prints nothing .... Why ? I read that Popen.wait is meant for its child process to terminate. Set and return returncode attribute. What is the child process here and why/how it is child O_O ?
3) If i only remove thread.join(timeout=1) then it finishes but with error Exception in thread Thread-1 (most likely raised during interpreter shutdown):. Why ? What role .join plays here.
4) I read the documentation of functions used in non_block_read function , but still am confused. Okay it is obvious they take file descriptor and set it to non blocking . The thing i am confused is , on what can i use all those functions , i mean i understand that on files , but how come they use it on stdout O_O ? It's not a file , it's a stream ~~ ?
All this i do to execute a script with subprocess.Popen in tornado script , and constantly send output to client/myself without blocking, so if anyone can kind of help me do that i would really appreciate it , because i can't imagine how to kind of get this output from thread in a way that i can constanly insert it in self.send in tornadio2 ...
def on_message(self, message):
# list = subprocess.Popen([r"ls", "-l"], stdout=subprocess.PIPE)
# list_stdout = list.communicate()[0]
for i in range(1,10):
time.sleep(1)
self.send(i)
With the dev version (3.2), that's realy easy
from tornado.web import RequestHandler,asynchronous
from tornado.process import Subprocess
class home(RequestHandler):
#asynchrounous
def get(self):
seld.sp=Subprocess('date && sleep 5 && date',shell=True,stdout=Subprocess.STREAM)
self.sp.set_exit_callback(self.next)
def next(self,s):
self.sp.stdout.read_until_close(self.finish)
application = ...