Tab-completion in Python interpreter in OS X Terminal - python

Several months ago, I wrote a blog post detailing how to achieve tab-completion in the standard Python interactive interpreter--a feature I once thought only available in IPython. I've found it tremendously handy given that I sometimes have to switch to the standard interpreter due to IPython unicode issues.
Recently I've done some work in OS X. To my discontent, the script doesn't seem to work for OS X's Terminal application. I'm hoping some of you with experience in OS X might be able to help me trouble-shoot it so it can work in Terminal, as well.
I am reproducing the code below
import atexit
import os.path
try:
import readline
except ImportError:
pass
else:
import rlcompleter
class IrlCompleter(rlcompleter.Completer):
"""
This class enables a "tab" insertion if there's no text for
completion.
The default "tab" is four spaces. You can initialize with '\t' as
the tab if you wish to use a genuine tab.
"""
def __init__(self, tab=' '):
self.tab = tab
rlcompleter.Completer.__init__(self)
def complete(self, text, state):
if text == '':
readline.insert_text(self.tab)
return None
else:
return rlcompleter.Completer.complete(self,text,state)
#you could change this line to bind another key instead tab.
readline.parse_and_bind('tab: complete')
readline.set_completer(IrlCompleter('\t').complete)
# Restore our command-line history, and save it when Python exits.
history_path = os.path.expanduser('~/.pyhistory')
if os.path.isfile(history_path):
readline.read_history_file(history_path)
atexit.register(lambda x=history_path: readline.write_history_file(x))
Note that I have slightly edited it from the version on my blog post so that the IrlCompleter is initialized with a true tab, which seems to be what is output by the Tab key in Terminal.

This should work under Leopard's python:
import rlcompleter
import readline
readline.parse_and_bind ("bind ^I rl_complete")
Whereas this one does not:
import readline, rlcompleter
readline.parse_and_bind("tab: complete")
Save it in ~/.pythonrc.py and execute in .bash_profile
export PYTHONSTARTUP=$HOME/.pythonrc.py

here is a full cross platform version of loading tab completion for Windows/OS X/Linux in one shot:
#Code UUID = '9301d536-860d-11de-81c8-0023dfaa9e40'
import sys
try:
import readline
except ImportError:
try:
import pyreadline as readline
# throw open a browser if we fail both readline and pyreadline
except ImportError:
import webbrowser
webbrowser.open("http://ipython.scipy.org/moin/PyReadline/Intro#line-36")
# throw open a browser
#pass
else:
import rlcompleter
if(sys.platform == 'darwin'):
readline.parse_and_bind ("bind ^I rl_complete")
else:
readline.parse_and_bind("tab: complete")
From http://www.farmckon.net/?p=181

To avoid having to use more GPL code, Apple doesn't include a real readline. Instead it uses the BSD-licensed libedit, which is only mostly-readline-compatible. Build your own Python (or use Fink or MacPorts) if you want completion.

This works for me on both Linux bash and OS X 10.4
import readline
import rlcompleter
readline.parse_and_bind('tab: complete')

If after trying the above, it still doesn't work, then try to execute in the shell:
sudo easy_install readline
Then, create ~/.profile file with the content:
export PYTHONSTARTUP=$HOME/.pythonrc.py
and a ~/.pythonrc.py file with the content:
try:
import readline
except:
print ("Module readline is not available.")
else:
import rlcompleter
readline.parse_and_bind("tab: complete")
Thanks to Steven Bamford for the easy_install tip, and Nicolas for the file content.

The documented way to tell libedit (the Mac OS semi-readline) from the real one is:
if "libedit" in readline.doc:
pass # Mac case
else:
pass # GNU readline case

After crashing into many issues dealing with Python (2 and 3) on FreeBSD, I finally got a proper extension to work using libedit directly as the completer for Python.
The basic issue with libedit/readline is that Python's completion and input was heavily bent towards GNU readline... Sadly, this is actually not a particularly good interface. It requires a giant number of globals in C and does not work well on an "instance" basis.
Solution:
https://github.com/mark-nicholson/python-editline
This is a true separate python extension which directly links to libedit using the actual "libedit" interface -- not the readline glue on the side.
I have tested it pretty thoroughly on Ubuntu, FreeBSD, OpenBSD, NetBSD and MacOS -- results are posted in the readme. The c-code is very clean and has virtually no platform dependent bits -- unlike the readline.c module in Python.
Notes:
It works on Python3 > 3.2.
It is NOT a drop-in replacement for 'import readline' in other scripts, but those scripts can be adjusted easily.
It can co-exist with readline.so -- there is code for a sitecustomize.py file which enables the selection.
It can use a distribution 'libedit.so', a custom built one or libedit built into the extension itself.

Related

How do you "Save as" /"open" a document using a Python Tkinter interface [duplicate]

I need to be able to open a document using its default application in Windows and Mac OS. Basically, I want to do the same thing that happens when you double-click on the document icon in Explorer or Finder. What is the best way to do this in Python?
Use the subprocess module available on Python 2.4+, not os.system(), so you don't have to deal with shell escaping.
import subprocess, os, platform
if platform.system() == 'Darwin': # macOS
subprocess.call(('open', filepath))
elif platform.system() == 'Windows': # Windows
os.startfile(filepath)
else: # linux variants
subprocess.call(('xdg-open', filepath))
The double parentheses are because subprocess.call() wants a sequence as its first argument, so we're using a tuple here. On Linux systems with Gnome there is also a gnome-open command that does the same thing, but xdg-open is the Free Desktop Foundation standard and works across Linux desktop environments.
open and start are command-interpreter things for Mac OS/X and Windows respectively, to do this.
To call them from Python, you can either use subprocess module or os.system().
Here are considerations on which package to use:
You can call them via os.system, which works, but...
Escaping: os.system only works with filenames that don't have any spaces or other shell metacharacters in the pathname (e.g. A:\abc\def\a.txt), or else these need to be escaped. There is shlex.quote for Unix-like systems, but nothing really standard for Windows. Maybe see also python, windows : parsing command lines with shlex
MacOS/X: os.system("open " + shlex.quote(filename))
Windows: os.system("start " + filename) where properly speaking filename should be escaped, too.
You can also call them via subprocess module, but...
For Python 2.7 and newer, simply use
subprocess.check_call(['open', filename])
In Python 3.5+ you can equivalently use the slightly more complex but also somewhat more versatile
subprocess.run(['open', filename], check=True)
If you need to be compatible all the way back to Python 2.4, you can use subprocess.call() and implement your own error checking:
try:
retcode = subprocess.call("open " + filename, shell=True)
if retcode < 0:
print >>sys.stderr, "Child was terminated by signal", -retcode
else:
print >>sys.stderr, "Child returned", retcode
except OSError, e:
print >>sys.stderr, "Execution failed:", e
Now, what are the advantages of using subprocess?
Security: In theory, this is more secure, but in fact we're needing to execute a command line one way or the other; in either environment, we need the environment and services to interpret, get paths, and so forth. In neither case are we executing arbitrary text, so it doesn't have an inherent "but you can type 'filename ; rm -rf /'" problem, and if the file name can be corrupted, using subprocess.call gives us little additional protection.
Error handling: It doesn't actually give us any more error detection, we're still depending on the retcode in either case; but the behavior to explicitly raise an exception in the case of an error will certainly help you notice if there is a failure (though in some scenarios, a traceback might not at all be more helpful than simply ignoring the error).
Spawns a (non-blocking) subprocess: We don't need to wait for the child process, since we're by problem statement starting a separate process.
To the objection "But subprocess is preferred." However, os.system() is not deprecated, and it's in some sense the simplest tool for this particular job. Conclusion: using os.system() is therefore also a correct answer.
A marked disadvantage is that the Windows start command requires you to pass in shell=True which negates most of the benefits of using subprocess.
I prefer:
os.startfile(path, 'open')
Note that this module supports filenames that have spaces in their folders and files e.g.
A:\abc\folder with spaces\file with-spaces.txt
(python docs) 'open' does not have to be added (it is the default). The docs specifically mention that this is like double-clicking on a file's icon in Windows Explorer.
This solution is windows only.
Just for completeness (it wasn't in the question), xdg-open will do the same on Linux.
import os
import subprocess
def click_on_file(filename):
'''Open document with default application in Python.'''
try:
os.startfile(filename)
except AttributeError:
subprocess.call(['open', filename])
If you have to use an heuristic method, you may consider webbrowser.
It's standard library and despite of its name it would also try to open files:
Note that on some platforms, trying to open a filename using this
function, may work and start the operating system’s associated
program. However, this is neither supported nor portable.
(Reference)
I tried this code and it worked fine in Windows 7 and Ubuntu Natty:
import webbrowser
webbrowser.open("path_to_file")
This code also works fine in Windows XP Professional, using Internet Explorer 8.
If you want to go the subprocess.call() way, it should look like this on Windows:
import subprocess
subprocess.call(('cmd', '/C', 'start', '', FILE_NAME))
You can't just use:
subprocess.call(('start', FILE_NAME))
because start is not an executable but a command of the cmd.exe program. This works:
subprocess.call(('cmd', '/C', 'start', FILE_NAME))
but only if there are no spaces in the FILE_NAME.
While subprocess.call method enquotes the parameters properly, the start command has a rather strange syntax, where:
start notes.txt
does something else than:
start "notes.txt"
The first quoted string should set the title of the window. To make it work with spaces, we have to do:
start "" "my notes.txt"
which is what the code on top does.
Start does not support long path names and white spaces. You have to convert it to 8.3 compatible paths.
import subprocess
import win32api
filename = "C:\\Documents and Settings\\user\\Desktop\file.avi"
filename_short = win32api.GetShortPathName(filename)
subprocess.Popen('start ' + filename_short, shell=True )
The file has to exist in order to work with the API call.
os.startfile(path, 'open') under Windows is good because when spaces exist in the directory, os.system('start', path_name) can't open the app correctly and when the i18n exist in the directory, os.system needs to change the unicode to the codec of the console in Windows.
I am pretty late to the lot, but here is a solution using the windows api. This always opens the associated application.
import ctypes
shell32 = ctypes.windll.shell32
file = 'somedocument.doc'
shell32.ShellExecuteA(0,"open",file,0,0,5)
A lot of magic constants. The first zero is the hwnd of the current program. Can be zero. The other two zeros are optional parameters (parameters and directory). 5 == SW_SHOW, it specifies how to execute the app.
Read the
ShellExecute API docs for more info.
Here is the answer from Nick, adjusted slightly for WSL:
import os
import sys
import logging
import subprocess
def get_platform():
if sys.platform == 'linux':
try:
proc_version = open('/proc/version').read()
if 'Microsoft' in proc_version:
return 'wsl'
except:
pass
return sys.platform
def open_with_default_app(filename):
platform = get_platform()
if platform == 'darwin':
subprocess.call(('open', filename))
elif platform in ['win64', 'win32']:
os.startfile(filename.replace('/','\\'))
elif platform == 'wsl':
subprocess.call('cmd.exe /C start'.split() + [filename])
else: # linux variants
subprocess.call(('xdg-open', filename))
If you want to specify the app to open the file with on Mac OS X, use this:
os.system("open -a [app name] [file name]")
On windows 8.1, below have worked while other given ways with subprocess.call fails with path has spaces in it.
subprocess.call('cmd /c start "" "any file path with spaces"')
By utilizing this and other's answers before, here's an inline code which works on multiple platforms.
import sys, os, subprocess
subprocess.call(('cmd /c start "" "'+ filepath +'"') if os.name is 'nt' else ('open' if sys.platform.startswith('darwin') else 'xdg-open', filepath))
On mac os you can call open:
import os
os.open("open myfile.txt")
This would open the file with TextEdit, or whatever app is set as default for this filetype.
I think you might want to open file in editor.
For Windows
subprocess.Popen(["notepad", filename])
For Linux
subprocess.Popen(["text-editor", filename])
I built a small library combining the best answers here for cross-platform support:
$ pip install universal-startfile
then launch a file or URL:
from startfile import startfile
startfile("~/Downloads/example.png")
startfile("http://example.com")
I was getting an error when calling my open file() function. I was following along with a guide but the guide was written in windows while I'm on Linux. So the os.statrfile method wasn't working for me. I was able to alleviate this problem by doing the following:
Import libraries
import sys, os, subprocess
import tkinter
import tkinter.filedioalog as fd
import tkinter.messagebox as mb
After the lib imports I then called the subprocess method for opening a file in unix based OS which is "xdg-open" and the file that will be opened.
def open_file():
file = fd.askopenfilename(title='Choose a file of any type', filetypes=[('All files', "*.*")])
subprocess.call(['xdg-open', file])

os.path.islink on windows with python

On Windows 7 with Python 2.7 how can I detect if a path is a symbolic link?
This does not work os.path.islink(), it says it returns false if false or not supported and the path I'm providing is definitely a symbolic link so I'm assuming it's not supported on windows? What can I do?
The root problem is that you're using too old a version of Python. If you want to stick to 2.x, you will not be able to take advantage of new features added after early 2010.
One of those features is handling NTFS symlinks. That functionality was added in 3.2 in late 2010. (See the 3.2, 3.1, and 2.7 source for details.)
The reason Python didn't handle NTFS symlinks before then is that there was no such thing until late 2009. (IIRC, support was included in the 6.0 kernel, but userland support requires a service pack on Vista/2008; only 7/2008R2 and newer come with it built in. Plus, you need a new-enough MSVCRT to be able to access that userland support, and Python has an explicit policy of not upgrading to new Visual Studio versions within a minor release.)
The reason the code wasn't ported back to 2.x is that there will never be a 2.8, and bug fix releases like 2.7.3 (or 2.7.4) don't get new features, only bug fixes.
This has been reported as issue 13143, and the intended fix is to change the 2.7 docs to clarify that islink always returns False on Windows.
So, if you want to read NTFS symlinks under Windows, either upgrade to Python 3.2+, or you have to use win32api, ctypes, etc. to do it yourself.
Or, as Martijn Pieters suggests, instead of doing it yourself, use a third-party library like jaraco.windows that does it and/or borrow their code.
Or, if you really want, borrow the code from the 3.2 source and build a C extension module around it. If you trace down from ntpath to os to nt (which is actually posixmodule.c), I believe the guts of it are in win32_xstat_impl and win32_xstat_impl_w.
This is what I ended up using to determine if a file or a directory is a link in Windows 7:
from subprocess import check_output, CalledProcessError
import os.path
import ctypes
def isLink(path):
if os.path.exists(path):
if os.path.isdir(path):
FILE_ATTRIBUTE_REPARSE_POINT = 0x0400
attributes = ctypes.windll.kernel32.GetFileAttributesW(unicode(path))
return (attributes & FILE_ATTRIBUTE_REPARSE_POINT) > 0
else:
command = ['dir', path]
try:
with open(os.devnull, 'w') as NULL_FILE:
o0 = check_output(command, stderr=NULL_FILE, shell=True)
except CalledProcessError as e:
print e.output
return False
o1 = [s.strip() for s in o0.split('\n')]
if len(o1) < 6:
return False
else:
return 'SYMLINK' in o1[5]
else:
return False
EDIT: Modified code as per suggestions of Zitrax and Annan
EDIT: Added include statements as per the suggestion of shioko
For directories:
import os, ctypes
def IsSymlink(path):
FILE_ATTRIBUTE_REPARSE_POINT = 0x0400
return os.path.isdir(path) and (ctypes.windll.kernel32.GetFileAttributesW(unicode(path)) & FILE_ATTRIBUTE_REPARSE_POINT):
Source
You can also use the pywin32 module: GetFileAttributes is available in the win32api sub-module and FILE_ATTRIBUTE_REPARSE_POINT in the win32con module. For instance, to test if a given path is a symlink to a directory, the code becomes:
import os
import win32api
import win32con
def is_directory_symlink(path):
return bool(os.path.isdir(path)
and (win32api.GetFileAttributes(path) &
win32con.FILE_ATTRIBUTE_REPARSE_POINT))
If using Python 2 and the path may contain non-ascii characters, GetFileAttributes requires a unicode string. However, simply using unicode(path) will generally fail: you should test if path is a str and, if so, use its decode method.
Just using if file[-4:len(file)] != ".lnk": works for me

Obtain Active window using Python

I would like to get the active window on the screen using python.
For example, the management interface of the router where you enter the username and password as admin
That admin interface is what I want to capture using python to automate the entry of username and password.
What imports would I require in order to do this?
On windows, you can use the python for windows extensions (http://sourceforge.net/projects/pywin32/):
from win32gui import GetWindowText, GetForegroundWindow
print GetWindowText(GetForegroundWindow())
Below code is for python 3:
from win32gui import GetWindowText, GetForegroundWindow
print(GetWindowText(GetForegroundWindow()))
(Found this on http://scott.sherrillmix.com/blog/programmer/active-window-logger/)
Thanks goes to the answer by Nuno André, who showed how to use ctypes to interact with Windows APIs. I have written an example implementation using his hints.
The ctypes library is included with Python since v2.5, which means that almost every user has it. And it's a way cleaner interface than old and dead libraries like win32gui (last updated in 2017 as of this writing). ((Update in late 2020: The dead win32gui library has come back to life with a rename to pywin32, so if you want a maintained library, it's now a valid option again. But that library is 6% slower than my code.))
Documentation is here: https://docs.python.org/3/library/ctypes.html (You must read its usage help if you wanna write your own code, otherwise you can cause segmentation fault crashes, hehe.)
Basically, ctypes includes bindings for the most common Windows DLLs. Here is how you can retrieve the title of the foreground window in pure Python, with no external libraries needed! Just the built-in ctypes! :-)
The coolest thing about ctypes is that you can Google any Windows API for anything you need, and if you want to use it, you can do it via ctypes!
Python 3 Code:
from typing import Optional
from ctypes import wintypes, windll, create_unicode_buffer
def getForegroundWindowTitle() -> Optional[str]:
hWnd = windll.user32.GetForegroundWindow()
length = windll.user32.GetWindowTextLengthW(hWnd)
buf = create_unicode_buffer(length + 1)
windll.user32.GetWindowTextW(hWnd, buf, length + 1)
# 1-liner alternative: return buf.value if buf.value else None
if buf.value:
return buf.value
else:
return None
Performance is extremely good: 0.01 MILLISECONDS on my computer (0.00001 seconds).
Will also work on Python 2 with very minor changes. If you're on Python 2, I think you only have to remove the type annotations (from typing import Optional and -> Optional[str]). :-)
Enjoy!
Win32 Technical Explanations:
The length variable is the length of the actual text in UTF-16 (Windows Wide "Unicode") CHARACTERS. (It is NOT the number of BYTES.) We have to add + 1 to add room for the null terminator at the end of C-style strings. If we don't do that, we would not have enough space in the buffer to fit the final real character of the actual text, and Windows would truncate the returned string (it does that to ensure that it fits the super important final string Null-terminator).
The create_unicode_buffer function allocates room for that many UTF-16 CHARACTERS.
Most (or all? always read Microsoft's MSDN docs!) Windows APIs related to Unicode text take the buffer length as CHARACTERS, NOT as bytes.
Also look closely at the function calls. Some end in W (such as GetWindowTextLengthW). This stands for "Wide string", which is the Windows name for Unicode strings. It's very important that you do those W calls to get proper Unicode strings (with international character support).
PS: Windows has been using Unicode for a long time. I know for a fact that Windows 10 is fully Unicode and only wants the W function calls. I don't know the exact cutoff date when older versions of Windows used other multi-byte string formats, but I think it was before Windows Vista, and who cares? Old Windows versions (even 7 and 8.1) are dead and unsupported by Microsoft.
Again... enjoy! :-)
UPDATE in Late 2020, Benchmark vs the pywin32 library:
import time
import win32ui
from typing import Optional
from ctypes import wintypes, windll, create_unicode_buffer
def getForegroundWindowTitle() -> Optional[str]:
hWnd = windll.user32.GetForegroundWindow()
length = windll.user32.GetWindowTextLengthW(hWnd)
buf = create_unicode_buffer(length + 1)
windll.user32.GetWindowTextW(hWnd, buf, length + 1)
return buf.value if buf.value else None
def getForegroundWindowTitle_Win32UI() -> Optional[str]:
# WARNING: This code sometimes throws an exception saying
# "win32ui.error: No window is is in the foreground."
# which is total nonsense. My function doesn't fail that way.
return win32ui.GetForegroundWindow().GetWindowText()
iterations = 1_000_000
start_time = time.time()
for x in range(iterations):
foo = getForegroundWindowTitle()
elapsed1 = time.time() - start_time
print("Elapsed 1:", elapsed1, "seconds")
start_time = time.time()
for x in range(iterations):
foo = getForegroundWindowTitle_Win32UI()
elapsed2 = time.time() - start_time
print("Elapsed 2:", elapsed2, "seconds")
win32ui_pct_slower = ((elapsed2 / elapsed1) - 1) * 100
print("Win32UI library is", win32ui_pct_slower, "percent slower.")
Typical result after doing multiple runs on an AMD Ryzen 3900x:
My function: 4.5769994258880615 seconds
Win32UI library: 4.8619983196258545 seconds
Win32UI library is 6.226762715455125 percent slower.
However, the difference is small, so you may want to use the library now that it has come back to life (it had previously been dead since 2017). But you're going to have to deal with that library's weird "no window is in the foreground" exception, which my code doesn't suffer from (see the code comments in the benchmark code).
Either way... enjoy!
The following script should work on Linux, Windows and Mac. It is currently only tested on Linux (Ubuntu Mate Ubuntu 15.10).
Prerequisites
For Linux:
Install wnck (sudo apt-get install python-wnck on Ubuntu, see libwnck.)
For Windows:
Make sure win32gui is available
For Mac:
Make sure AppKit is available
The script
#!/usr/bin/env python
"""Find the currently active window."""
import logging
import sys
logging.basicConfig(format='%(asctime)s %(levelname)s %(message)s',
level=logging.DEBUG,
stream=sys.stdout)
def get_active_window():
"""
Get the currently active window.
Returns
-------
string :
Name of the currently active window.
"""
import sys
active_window_name = None
if sys.platform in ['linux', 'linux2']:
# Alternatives: https://unix.stackexchange.com/q/38867/4784
try:
import wnck
except ImportError:
logging.info("wnck not installed")
wnck = None
if wnck is not None:
screen = wnck.screen_get_default()
screen.force_update()
window = screen.get_active_window()
if window is not None:
pid = window.get_pid()
with open("/proc/{pid}/cmdline".format(pid=pid)) as f:
active_window_name = f.read()
else:
try:
from gi.repository import Gtk, Wnck
gi = "Installed"
except ImportError:
logging.info("gi.repository not installed")
gi = None
if gi is not None:
Gtk.init([]) # necessary if not using a Gtk.main() loop
screen = Wnck.Screen.get_default()
screen.force_update() # recommended per Wnck documentation
active_window = screen.get_active_window()
pid = active_window.get_pid()
with open("/proc/{pid}/cmdline".format(pid=pid)) as f:
active_window_name = f.read()
elif sys.platform in ['Windows', 'win32', 'cygwin']:
# https://stackoverflow.com/a/608814/562769
import win32gui
window = win32gui.GetForegroundWindow()
active_window_name = win32gui.GetWindowText(window)
elif sys.platform in ['Mac', 'darwin', 'os2', 'os2emx']:
# https://stackoverflow.com/a/373310/562769
from AppKit import NSWorkspace
active_window_name = (NSWorkspace.sharedWorkspace()
.activeApplication()['NSApplicationName'])
else:
print("sys.platform={platform} is unknown. Please report."
.format(platform=sys.platform))
print(sys.version)
return active_window_name
print("Active window: %s" % str(get_active_window()))
For Linux users:
All the answers provided required additional modules like "wx" that had numerous errors installing ("pip" failed on build), but I was able to modify this solution quite easily -> original source. There were bugs in the original (Python TypeError on regex)
import sys
import os
import subprocess
import re
def get_active_window_title():
root = subprocess.Popen(['xprop', '-root', '_NET_ACTIVE_WINDOW'], stdout=subprocess.PIPE)
stdout, stderr = root.communicate()
m = re.search(b'^_NET_ACTIVE_WINDOW.* ([\w]+)$', stdout)
if m != None:
window_id = m.group(1)
window = subprocess.Popen(['xprop', '-id', window_id, 'WM_NAME'], stdout=subprocess.PIPE)
stdout, stderr = window.communicate()
else:
return None
match = re.match(b"WM_NAME\(\w+\) = (?P<name>.+)$", stdout)
if match != None:
return match.group("name").strip(b'"')
return None
if __name__ == "__main__":
print(get_active_window_title())
The advantage is it works without additional modules. If you want it to work across multiple platforms, it's just a matter of changing the command and regex strings to get the data you want based on the platform (with the standard if/else platform detection shown above sys.platform).
On a side note: import wnck only works with python2.x when installed with "sudo apt-get install python-wnck", since I was using python3.x the only option was pypie which I have not tested. Hope this helps someone else.
There's really no need to import any external dependency for tasks like this. Python comes with a pretty neat foreign function interface - ctypes, which allows for calling C shared libraries natively. It even includes specific bindings for the most common Win32 DLLs.
E.g. to get the PID of the foregorund window:
import ctypes
from ctypes import wintypes
user32 = ctypes.windll.user32
h_wnd = user32.GetForegroundWindow()
pid = wintypes.DWORD()
user32.GetWindowThreadProcessId(h_wnd, ctypes.byref(pid))
print(pid.value)
In Linux under X11:
xdo_window_id = os.popen('xdotool getactivewindow').read()
print('xdo_window_id:', xdo_window_id)
will print the active window ID in decimal format:
xdo_window_id: 67113707
Note xdotool must be installed first:
sudo apt install xdotool
Note wmctrl uses hexadecimal format for window ID.
This only works on windows
import win32gui
import win32process
def get_active_executable_name():
try:
process_id = win32process.GetWindowThreadProcessId(
win32gui.GetForegroundWindow()
)
return ".".join(psutil.Process(process_id[-1]).name().split(".")[:-1])
except Exception as exception:
return None
I'll recommend checking out this answer for making it work on linux, mac and windows.
I'd been facing same problem with linux interface (Lubuntu 20).
What I do is using wmctrl and execute it with shell command from python.
First, Install wmctrl
sudo apt install wmctrl
Then, Add this code :
import os
os.system('wmctrl -a "Mozilla Firefox"')
ref wmctrl :
https://askubuntu.com/questions/21262/shell-command-to-bring-a-program-window-in-front-of-another
In Linux:
If you already have installed xdotool, you can just use:
from subprocess import run
def get__focused_window():
return run(['xdotool', 'getwindowfocus', 'getwindowpid', 'getwindowname'], capture_output=True).stdout.decode('utf-8').split()
While I was writing this answer I've realised that there were also:
A reference about "xdotool" on comments
& another slightly similar "xdotool" answer
So, I've decided to mention them here, too.
Just wanted to add in case it helps, I have a function for my program (It's a software for my PC's lighting I have this simple few line function:
def isRunning(process_name):
foregroundWindow = GetWindowText(GetForegroundWindow())
return process_name in foregroundWindow
Try using wxPython:
import wx
wx.GetActiveWindow()

pythonrc in interactive code

I have a .pythonrc in my path, which gets loaded when I run python:
python
Loading pythonrc
>>>
The problem is that my .pythonrc is not loaded when I execute files:
python -i script.py
>>>
It would be very handy to have tab completion (and a few other things) when I load things interactively.
From the Python documentation for -i:
When a script is passed as first argument or the -c option is used, enter interactive mode after executing the script or the command, even when sys.stdin does not appear to be a terminal. The PYTHONSTARTUP file is not read.
I believe this is done so that scripts run predictably for all users, and do not depend on anything in a user's particular PYTHONSTARTUP file.
As Greg has noted, there is a very good reason why -i behaves the way it does. However, I do find it pretty useful to be able to have my PYTHONSTARTUP loaded when I want an interactive session. So, here's the code I use when I want to be able to have PYTHONSTARTUP active in a script run with -i.
if __name__ == '__main__':
#do normal stuff
#and at the end of the file:
import sys
if sys.flags.interactive==1:
import os
myPythonPath = os.environ['PYTHONSTARTUP'].split(os.sep)
sys.path.append(os.sep.join(myPythonPath[:-1]))
pythonrcName = ''.join(myPythonPath[-1].split('.')[:-1]) #the filename minus the trailing extension, if the extension exists
pythonrc = __import__(pythonrcName)
for attr in dir(pythonrc):
__builtins__.__dict__[attr] = getattr(pythonrc, attr)
sys.path.remove(os.sep.join(myPythonPath[:-1]))
del sys, os, pythonrc
Note that this is fairly hacky and I never do this without ensuring that my pythonrc isn't accidentally clobbering variables and builtins.
Apparently the user module provides this, but has been removed in Python 3.0. It is a bit of a security hole, depending what's in your pythonrc...
In addition to Chinmay Kanchi and Greg Hewgill's answers, I'd like to add that IPython and BPython work fine in this case. Perhaps it's time for you to switch? :)

Use Python 2.6 subprocess module in Python 2.5

I would like to use Python 2.6's version of subprocess, because it allows the Popen.terminate() function, but I'm stuck with Python 2.5. Is there some reasonably clean way to use the newer version of the module in my 2.5 code? Some sort of from __future__ import subprocess_module?
I know this question has already been answered, but for what it's worth, I've used the subprocess.py that ships with Python 2.6 in Python 2.3 and it's worked fine. If you read the comments at the top of the file it says:
# This module should remain compatible with Python 2.2, see PEP 291.
There isn't really a great way to do it. subprocess is implemented in python (as opposed to C) so you could conceivably copy the module somewhere and use it (hoping of course that it doesn't use any 2.6 goodness).
On the other hand you could simply implement what subprocess claims to do and write a function that sends SIGTERM on *nix and calls TerminateProcess on Windows. The following implementation has been tested on linux and in a Win XP vm, you'll need the python Windows extensions:
import sys
def terminate(process):
"""
Kills a process, useful on 2.5 where subprocess.Popens don't have a
terminate method.
Used here because we're stuck on 2.5 and don't have Popen.terminate
goodness.
"""
def terminate_win(process):
import win32process
return win32process.TerminateProcess(process._handle, -1)
def terminate_nix(process):
import os
import signal
return os.kill(process.pid, signal.SIGTERM)
terminate_default = terminate_nix
handlers = {
"win32": terminate_win,
"linux2": terminate_nix
}
return handlers.get(sys.platform, terminate_default)(process)
That way you only have to maintain the terminate code rather than the entire module.
While this doesn't directly answer your question, it may be worth knowing.
Imports from __future__ actually only change compiler options, so while it can turn with into a statement or make string literals produce unicodes instead of strs, it can't change the capabilities and features of modules in the Python standard library.
I followed Kamil Kisiel suggestion regarding using python 2.6 subprocess.py in python 2.5 and it worked perfectly. To make it easier, I created a distutils package that you can easy_install and/or include in buildout.
To use subprocess from python 2.6 in python 2.5 project:
easy_install taras.python26
in your code
from taras.python26 import subprocess
in buildout
[buildout]
parts = subprocess26
[subprocess26]
recipe = zc.recipe.egg
eggs = taras.python26
Here are some ways to end processes on Windows, taken directly from
http://code.activestate.com/recipes/347462/
# Create a process that won't end on its own
import subprocess
process = subprocess.Popen(['python.exe', '-c', 'while 1: pass'])
# Kill the process using pywin32
import win32api
win32api.TerminateProcess(int(process._handle), -1)
# Kill the process using ctypes
import ctypes
ctypes.windll.kernel32.TerminateProcess(int(process._handle), -1)
# Kill the proces using pywin32 and pid
import win32api
PROCESS_TERMINATE = 1
handle = win32api.OpenProcess(PROCESS_TERMINATE, False, process.pid)
win32api.TerminateProcess(handle, -1)
win32api.CloseHandle(handle)
# Kill the proces using ctypes and pid
import ctypes
PROCESS_TERMINATE = 1
handle = ctypes.windll.kernel32.OpenProcess(PROCESS_TERMINATE, False, process.pid)
ctypes.windll.kernel32.TerminateProcess(handle, -1)
ctypes.windll.kernel32.CloseHandle(handle)
Well Python is open source, you are free to take that pthread function from 2.6 and move it into your own code or use it as a reference to implement your own.
For reasons that should be obvious there's no way to have a hybrid of Python that can import portions of newer versions.

Categories

Resources