Python get specific window title - python

I want to be able to detect the presence of a specifically named window (in any process) to use as an "if" variable
After some research, I've concluded I must use the win32gui library (some posts also suggest ctypes), but most of the posts I find are about making a list of processes, and the only one that was related to this topic didn't answer the question properly. Perhaps I am too novice to understand it, but at last, I couldn't get it to work (the question was this one)
To exemplify what I want, I'll share a simple .vbs code that does that: It searches for a specific name (in our case, steve jobs) and if it finds it anywhere, it triggers (in this example, it closes said process)
do
WindowTitle = "steve jobs"
set shell = createObject("wscript.shell")
success = shell.appactivate(WindowTitle)
if success then shell.sendkeys "%{F4}"
loop

import win32gui
win2find = input('enter name of window to find')
whnd = win32gui.FindWindowEx(None, None, None, win2find)
if not (whnd == 0):
print('FOUND!')
You can search Google for 'FindWindowEx'
to find https://msdn.microsoft.com/en-us/library/windows/desktop/ms633500(v=vs.85).aspx
for a description of the FindWindowEx function

Related

Can't open Microsoft Teams with python (3.8) script using any method

I am trying to make a script to automate the login into Microsoft Teams and all of my code works except the part where the application has to be opened. The weird thing is that this is capable of opening any other application except MS Teams (Chrome, Notepad, Firefox, Edge etc.)
Here's the relevant code:
def openfile():
if os.stat("stor.txt").st_size == 0:
name = filedialog.askopenfilename()
newfile = open("stor.txt", "w")
newfile.write(name)
else:
name = (open("stor.txt", "r").read())
os.startfile(name)
sleep(5)
keyboard.write(open("user.txt", "r").read())
keyboard.press("enter")
sleep(3)
keyboard.write(open("pass.txt", "r").read())
keyboard.press("enter")
I tried this with os.startfile, os.system(start..) and every other method on the web. Doesn't work.
The value I'm passing in to os.startfile() when I try to run Teams is C:/Users/Raghav/AppData/Local/Microsoft/Teams/Update.exe.
First of all, I don't recommend storing your password in plain text like that. It's not very secure, and if another program takes focus at the right time your code will even type your password somewhere else!
Teams should remember your credentials after the first time you log in. I suggest letting it handle that part.
In any case, running os.startfile("foo.exe") is like double-clicking on foo.exe. The file name that you're passing in is C:/Users/Raghav/AppData/Local/Microsoft/Teams/Update.exe, and Update.exe doesn't look like something that should launch Teams to me.
Inspecting the Teams shortcut in my own Start menu, I see that things are a bit more complicated. This shortcut runs Update.exe and passes it some arguments:
C:\...\Update.exe --processStart "Teams.exe"
There is no way to pass arguments to a program with os.startfile(). Try os.system() instead:
os.system('C:/Users/Raghav/AppData/Local/Microsoft/Teams/Update.exe --processStart "Teams.exe"')
There are lots of other ways to run external commands in Python, but this is likely simplest since you don't need Teams' output streams. This command should return 0 if it succeeds and some other value if it fails.
import os
os.system("C:\\Users\\Lenovo\\AppData\\Local\\Discord\\Update.exe --processStart Discord.exe")
For applications that have an address like above, there are also some tips:
Sometimes Discord.exe name of the file in the address have "Discord.exe" (with double-quotes). Remove it.
Instead of single \ use double \\ in the address.
It will definitely work GO AHEAD ✔

Python script entry point: How to call "__main__2"?

I have inherited a python script which appears to have multiple distinct entry points. For example:
if __name__ == '__main__1':
... Do stuff for option 1
if __name__ == '__main__2':
... Do stuff for option 2
etc
Google has turned up a few other examples of this syntax (e.g. here) but I'm still no wiser on how to use it.
So the question is: How can I call a specific entry point in a python script that has multiple numbered __main__ sections?
Update:
I found another example of it here, where the syntax appears to be related to a specfic tool.
https://github.com/brython-dev/brython/issues/163
The standard doc mentions only main as a reserved module namespace. After looking at your sample I notice that every main method seems separate, does its imports, performs some enclosed functionality. My suspicion is that the developer wanted to quickly swap functionalities and didn't bother to use command line arguments for that, opting instead to swap 'main2' to 'main' as needed.
This is by no means proven, though - any chance of contacting the one who wrote this in the first place?

Using conditional imports as a way to utilize different functions with the same namespace

I am a beginner python programmer, and I am working on a selenium project in python 2.7.
I have a generic scraper script, that basically outlines what I want to do with all the websites that I visit. However, because of the nature of the data that I want to grab, I can't run the same code on each site-- each site needs to run it's own individual code.
I have attempted to solve this by importing inside of an if statement, and this is the solution I came up with:
site = False
if source_website == "Website A":
from website_a import *
site = True
elif source_website == "Website B":
from website_b import *
site = True
else:
print "This is not an acceptable website!"
if site == True:
# main code block
driver = driver_setup(chrome)
driver.get(source_website_URL)
stuff_to_save = do_some_stuff(driver)
xml_file(stuff_to_save)
driver.quit()
where the website_a and website_b modules both have functions named do_some_stuff, and they do stuff specific to the website that they're on. Now, this seems to work, for the most part. I also seem to be able to extend functionality to any number of websites, given that I program a module called website_c with the function do_some_stuff, and add that to the conditional import.
So, my question is, is this a good idea? Is there a better way to do something like this?
I have literally never seen anyone wrap import statements inside of if statements like this-- and generally, if no one seems to do it, there's usually a good reason why.
In general, from somewhere import * is not a good idea due to namespace pollution. If you want the website-specific code in separate modules, why not do something like
import importlib
website_modules = {'Website A': 'website_a', 'Website B': 'website_b'}
# ...
website = importlib.import_module(website_modules[source_website])
# use with website.function_name
Explore the page object model pattern (http://code.google.com/p/selenium/wiki/PageObjects). You should model each page as a unique entity, then have some logic that determines what page type you are displaying (either explicitly by having you specify it or implicitly by inspecting the URL and the contents of the page) and then expose the methods to capture the data you need on those objects rather than working directly with the webdriver instance. You should ultimately aim for something like:
for page_identifier in ['page1', 'page2', 'page3']:
page = navigate_to(page_identifier)
extracted_data = page.get_data()
xml_file.write(extracted_data)

python curses addstr error - but only on my computer

I was writing a little program that takes a list and generates a menu out of it in curses (straight up, standard library or whatever, batteries included python's curses) when I noticed the strangest problem (if you'd like, a heavily commented copy of the entire program is below). Simply put, when accepting the results of an os.listdir generated list, curses crashes with an addstr ERR, BUT, if I feed it a hardcoded list, it works fine. This, of course, makes absolutely no sense, right? A list is a list is a list and a list by any other name should still be a list, right?
To make things even more complicated, I sent the code to a friend of mine who works mainly in python2.6 (mine was originally written to work in python3.1). He uncommented the broken_input() call (which feeds the program the os.listdir generated information) and said that it worked fine for him. I have both python 2.6 and 3.1 installed, so I changed my shebang to make the program run in 2.6, and (with the broken_input() uncommented) for me, it still throws the addstr ERR (yet runs fine with the hardcoded input... which is, of course, btw, entirely useless apart from proof of concept).
Thus, my question is this: is there something broken in my python installation (I'm running Ubuntu lucid, with python2.6.5 and 3.1 installed), and, if so, how do I fix it so I can get curses to execute this code properly. And, if it's not my python installation, how can I get the same functionality out of curses (i.e.: paint a menu from a list containing an arbitrary number of items, numbering them so that the user can make a selection based on the item number).
#!/usr/bin/env python3.1
"""curses_mp3eater.py: a curses-based implementation of my mp3eater program;
diplays the contents of cwd, allows user to make a selection. But I'm having
problems getting it to iterate over a list.
v0.1 03.14.11
by skookie sprite
address#gmail.com
"""
import curses, curses.wrapper, os, sys
def working_input():
"""the following is demo code to demonstrate my problem... main will accept the following,
but won't accept the product of a directorylist for reasons that I can't figure out."""
dircontents=['this','is','a','list','','and','it','will','iterate','fine','in','the','(main) function.']
return dircontents
def broken_input():
"""this is the code that I NEED to have work... but for reasons beyond me will not iterate in
the main function. It's a simple list of the contents of the CWD."""
cwd=os.getcwd()
dircontents=[]
for item in os.listdir(cwd):
dircontents += [item]
return dircontents
def main(stdscr):
"""This is the program. Designed to take a list of stuff and display it. If I can solve
that hurdle, I'll add selection mechanisms, and break it across screens - amongst other
things. But, currently, it can only accept the demo code. Uncomment one or the other to
see what I mean."""
#broken_input returns an addstr() ERR, but I don't see the difference between working_input
#and broken_input as they are both just lists.
#working_input() is demo code that illustrates my problem
stuffin=working_input()
#stuffin=broken_input()
#the rest of this stuff works. The problem is with the input. Why?
linenumber=int()
linenumber=6
itemnumber=int()
itemnumber=1
stdscr.clear()
stdscr.border(0)
for item in stuffin:
stdscr.addstr(linenumber, 10, '%s - %s' % (itemnumber, item), curses.A_NORMAL)
linenumber += 1
itemnumber += 1
curses.doupdate()
stdscr.getch()
if __name__ == '__main__':
curses.wrapper(main)
You're stuffing too much onto the screen and thus passing an out-of-bounds line number to addstr. If you make an empty directory to run the program in (or enlarge your terminal window), it works.
To fix this, check the number of lines in the window before the output loop in main.
use screen.scrollok(1) after addstr to allow the text to scroll.
The problem is explained in the addch manual page:
The addch, waddch, mvaddch and mvwaddch routines put the character ch
into the given window at its current window position, which is then
advanced. They are analogous to putchar(3) in stdio(3). If the
advance is at the right margin:
The cursor automatically wraps to the beginning of the next line.
At the bottom of the current scrolling region, and if scrollok is
enabled, the scrolling region is scrolled up one line.
If scrollok is not enabled, writing a character at the lower right
margin succeeds. However, an error is returned because it is not
possible to wrap to a new line
The given program neither catches an error from the lower right margin (probably should say "corner"), nor calls scrollok to allow the data to scroll up. In the latter case, you will lose information which is scrolled up, while handling the exception would allow you to prompt after a screen's worth of data is displayed, and then either quit or display more data.

"Unknown object" error when trying to capture artwork from a pict file and embed it into a track

I'm trying to capture artwork from a pict file and embed it into a track on iTunes using python appscript.
I did something like this:
imFile = open('/Users/kartikaiyer/temp.pict','r')
data = imFile.read()
it = app('iTunes')
sel = it.current_track.get()
sel.artworks[0].data_.set(data[513:])
I get an error OSERROR: -1731
MESSAGE: Unknown object
Similar applescript code looks like this:
tell application "iTunes"
set the_artwork to read (POSIX file "/Users/kartikaiyer/temp.pict") from 513 as picture
set data of artwork 1 of current track to the_artwork
end tell
I tried using ASTranslate but it never instantiates the_artwork and then throws an error when there is a reference to the_artwork.
This is an older question, but since I was having trouble doing this same thing now, I thought I'd post my solution in case someone else might benefit.
selected = appscript.app('iTunes').selection.get()
for t in selected:
myArt = open(/path/to/image.jpg,'r')
data = myArt.read()
t.artworks[1].data_.set(data) # no need to remove header but one-indexed as has said earlier
myArt.close()
Hope this helps.
At a quick guess, Appscript references, like AppleScript references, use 1-indexing, not zero-indexing like Python lists. So you probably need to write:
it.current_track.artworks[1].data_.set(...)
(Incidentally, the extra get command in your original script is unnecessary, though harmless in this case.)
As for ASTranslate, you need to enable the 'Send events to app' checkbox if you want it to actually send commands to applications and scripting additions and receive their results. As a rule, it's best to disable this option so that you don't have any unfortunate accidents when translating potentially destructive commands such as set or delete, so only to enable it if you really need it, and be careful what code you run when you do.
The read command is part of Scripting Additions, which ASTranslate doesn't translate to. Use ASDictionary to create a glue for Scripting Additions, by clicking "Choose Installed Scripting Additions" Under the Dictionary menu, and then selecting "Scripting Additions" from the list.

Categories

Resources