Pexpect not matching (control codes) - python

Pexpect script running against a Casa CMTS/router.
I have working implementations of this script for Cisco and Adva devices, so I know the technique is sound, but for some reason i'm having issues with a specific expectation.
I'm trying to match a simple
:
However, the following code does not work:
def handleAllPrompts(self):
while self.child.after == ":":
print "waiting"
self.child.expect(":", 20)
try:
self.child.expect("\>\ *$|#\ *$|\$\ *$", 20)
except pexpect.exceptions.TIMEOUT as e:
print self.child.before
This is supposed to automatically handle the "more" prompt when doing something like a show run that has multiple screens of output.
Pexpect crashes with this info:
before (last 100 chars): 'sis downstream channel utilization"\r\nalias save "copy run start"\r\nalias scm "show cable modem"\r\n:\x1b[K'
I'm trying to detect the last colon (:\x1b[K), however as you can see it's a colon+term control code.
But doing:
def handleAllPrompts(self):
while self.child.after == ":\x1b[K":
print "waiting"
self.child.expect(":\x1b[K", 20)
try:
self.child.expect("\>\ *$|#\ *$|\$\ *$", 20)
except pexpect.exceptions.TIMEOUT as e:
print self.child.before
Doesn't work either.
Any thoughts?

Related

How to program hotstrings in python like in autohotkey

I want to make hotstrings in python that converts one word when typed into another after some processing, since AHK is very limiting when it comes to determining which word to type. Right now, I am using a hotstring in ahk that runs code on the command line that runs a python script with the word that I typed as arguments. Then I use pyautogui to type the word. However, this is very slow and does not work when typing at speed. I'm looking for a way to do this all with python and without ahk, but I have not found a way to do hotstrings in python. For example, every time I type the word "test" it replaces it with "testing." Thanks for your help. I'm running the latest version of Python and Windows 10 if that is useful to anyone by the way.
(if you want to process it as each letter is typed(t,te,tes,test), you should edit your question)
I call my SymPy functions using ahk hotkeys. I register the python script as a COM server and load it using ahk.
I do not notice any latency.
you'll need pywin32, but don't download using pip install pywin32
download from https://github.com/mhammond/pywin32/releases
OR ELSE IT WON'T WORK for AutoHotkeyU64.exe, it will only work for AutoHotkeyU32.exe.
make sure to download amd64, (I downloaded pywin32-300.win-amd64-py3.8.exe)
here's why: how to register a 64bit python COM server
toUppercase COM server.py
class BasicServer:
# list of all method names exposed to COM
_public_methods_ = ["toUppercase"]
#staticmethod
def toUppercase(string):
return string.upper()
if __name__ == "__main__":
import sys
if len(sys.argv) < 2:
print("Error: need to supply arg (""--register"" or ""--unregister"")")
sys.exit(1)
else:
import win32com.server.register
import win32com.server.exception
# this server's CLSID
# NEVER copy the following ID
# Use "print(pythoncom.CreateGuid())" to make a new one.
myClsid="{C70F3BF7-2947-4F87-B31E-9F5B8B13D24F}"
# this server's (user-friendly) program ID
myProgID="Python.stringUppercaser"
import ctypes
def make_sure_is_admin():
try:
if ctypes.windll.shell32.IsUserAnAdmin():
return
except:
pass
exit("YOU MUST RUN THIS AS ADMIN")
if sys.argv[1] == "--register":
make_sure_is_admin()
import pythoncom
import os.path
realPath = os.path.realpath(__file__)
dirName = os.path.dirname(realPath)
nameOfThisFile = os.path.basename(realPath)
nameNoExt = os.path.splitext(nameOfThisFile)[0]
# stuff will be written here
# HKEY_LOCAL_MACHINE\SOFTWARE\Classes\CLSID\${myClsid}
# HKEY_LOCAL_MACHINE\SOFTWARE\Classes\CLSID\{C70F3BF7-2947-4F87-B31E-9F5B8B13D24F}
# and here
# HKEY_LOCAL_MACHINE\SOFTWARE\Classes\${myProgID}
# HKEY_LOCAL_MACHINE\SOFTWARE\Classes\Python.stringUppercaser
win32com.server.register.RegisterServer(
clsid=myClsid,
# I guess this is {fileNameNoExt}.{className}
pythonInstString=nameNoExt + ".BasicServer", #toUppercase COM server.BasicServer
progID=myProgID,
# optional description
desc="return uppercased string",
#we only want the registry key LocalServer32
#we DO NOT WANT InProcServer32: pythoncom39.dll, NO NO NO
clsctx=pythoncom.CLSCTX_LOCAL_SERVER,
#this is needed if this file isn't in PYTHONPATH: it tells regedit which directory this file is located
#this will write HKEY_LOCAL_MACHINE\SOFTWARE\Classes\CLSID\{C70F3BF7-2947-4F87-B31E-9F5B8B13D24F}\PythonCOMPath : dirName
addnPath=dirName,
)
print("Registered COM server.")
# don't use UseCommandLine(), as it will write InProcServer32: pythoncom39.dll
# win32com.server.register.UseCommandLine(BasicServer)
elif sys.argv[1] == "--unregister":
make_sure_is_admin()
print("Starting to unregister...")
win32com.server.register.UnregisterServer(myClsid, myProgID)
print("Unregistered COM server.")
else:
print("Error: arg not recognized")
you first need to register the python COM server:
first, get your own CLSID: just use a python shell.
import pythoncom
print(pythoncom.CreateGuid())
then, set myClsid to that output
to register:
python "toUppercase COM server.py" --register
to unregister:
python "toUppercase COM server.py" --unregister
hotstring python toUppercase.ahk
#NoEnv ; Recommended for performance and compatibility with future AutoHotkey releases.
#SingleInstance, force
SendMode Input ; Recommended for new scripts due to its superior speed and reliability.
SetWorkingDir %A_ScriptDir% ; Ensures a consistent starting directory.
SetBatchLines, -1
#KeyHistory 0
ListLines Off
#Persistent
#MaxThreadsPerHotkey 4
pythonComServer:=ComObjCreate("Python.stringUppercaser")
; OR
; pythonComServer:=ComObjCreate("{C70F3BF7-2947-4F87-B31E-9F5B8B13D24F}") ;use your own CLSID
; * do not wait for string to end
; C case sensitive
:*:hello world::
savedHotstring:=A_ThisHotkey
;theActualHotstring=savedHotstring[second colon:end of string]
theActualHotstring:=SubStr(savedHotstring, InStr(savedHotstring, ":",, 2) + 1)
send, % pythonComServer.toUppercase(theActualHotstring)
return
f3::Exitapp
you can test the speed of hotstring hello world, it's very fast for me.
Edit def toUppercase(string): to your liking

Py program gives an error if I dont open it with interactive shell

I 've a porgram called searchMachine.py that if I run it straight from IDLE (F5..)it works just fine, but If I run it by just clicking on searchMachine.py it works untill somepoint and then I get an error. See below.
Thanks for any input you could give me.
By the way, any idea how I can make this chrome work in silent? for example minimized?
from selenium import webdriver
from selenium.webdriver.support.ui import Select
print('Please type the machine name.')
machinename = input()
print('')
print('Thank you.')
print('')
print('Results will show below.')
print('')
path_to_chromedriver = 'C:\python34\chromedriver\chromedriver.exe' # change path as needed
browser = webdriver.Chrome(executable_path = path_to_chromedriver)
url = 'http://app.corp'
browser.get(url)
browser.find_element_by_xpath("/html/body/div[4]/form/table[1]/tbody/tr/td[5]/input[1]").send_keys(machinename)
browser.find_element_by_css_selector('input[type=\"submit\"]').click() # working to press submit
xpath = '/html/body/div[4]/form/center[2]/table/thead'
for i in browser.find_elements_by_xpath(xpath):
print (i.text)
xpath = '/html/body/div[4]/form/center[2]/table/tbody/tr'
for i in browser.find_elements_by_xpath(xpath):
print (i.text)
browser.close()
import os
os.system("c:/code/close_chrome_driver.bat")
error is:
The error occurs because the unicode character ▾ or U+25BE BLACK DOWN-POINTING SMALL TRIANGLE cannot be written into Windows console window, as it does not have a match in the CP850 character set as used by your Windows console.
Now, Python croaks loudly when it cannot print the correct value. You could set the PYTHONIOENCODING environment variable to say cp850:ignore which would make the Python process ignore errors; or you can print to stderr instead of stdout, which would use the backslashescape error handling.

Executable out of script containing serial_for_url

I have developed a python script for making a serial communication to a digital pump. I now need to make an executable out of it. However even though it works perfectly well when running it with python and py2exe does produce the .exe properly when I run the executable the following error occurs:
File: pump_model.pyc in line 96 in connect_new
File: serial\__init__.pyc in line 71 in serial_for_url
ValueError: invalid URL protocol 'loop' not known
The relevant piece of my code is the following:
# New serial connection
def connect_new(self, port_name):
"""Function for configuring a new serial connection."""
try:
self.ser = serial.Serial(port = port_name,\
baudrate = 9600,\
parity = 'N',\
stopbits = 1,\
bytesize = 8,\
timeout = self.timeout_time)
except serial.SerialException:
self.ser = serial.serial_for_url('loop://',\
timeout = self.timeout_time) # This line BLOWS!
except:
print sys.exc_info()[0]
finally:
self.initialize_pump()
I should note that the application was written in OSX and was tested on Windows with the Canopy Python Distribution.
I had the exact same problem with "socket://" rather than "loop://"
I wasn't able to get the accepted answer to work however the following seems to succeed:
1) Add an explicit import of the offending urlhandler.* module
import serial
# explicit import for py2exe - to fix "socket://" url issue
import serial.urlhandler.protocol_socket
# explicit import for py2exe - to fix "loop://" url issue (OP's particular prob)
import serial.urlhandler.protocol_loop
# use serial_for_url in normal manner
self._serial = serial.serial_for_url('socket://192.168.1.99:12000')
2) Generate a setup script for py2exe (see https://pypi.python.org/pypi/py2exe/) -- I've installed py2exe to a virtualenv:
path\to\env\Scripts\python.exe -m py2exe myscript.py -W mysetup.py
3) edit mysetup.py to include option
zipfile="library.zip" # default generated value is None
(see also http://www.py2exe.org/index.cgi/ListOfOptions)
3) build it:
path\to\env\Scripts\python.exe mysetup.py py2exe
4) run it
dist\myscript.exe
Found it!
It seems that for some reason the 'loop://' arguement can't be recognised after the .exe production.
I figured out by studying the pyserial/init.py script that when issuing the command serial.serial_for_url(‘loop://') you essentially call:
sys.modules['serial.urlhandler.protocol_loop’].Serial(“loop://“)
So you have to first import the serial.urlhandler.protocol_loop
and then issue that command in place of the one malfunctioning.
So you can now type:
__import__('serial.urlhandler.protocol_loop')
sys.modules[‘serial.urlhandler.protocol_loop’].Serial("loop://")
After this minor workaround it worked fine.

python script to detect hot-plug event

I'm trying to use python to detect mouse and keyboard event, and tolerant the hot-plug action during the detection. I write this script to automatically detect the keyboard and mouse plug-ins in run-time and output all the keyboard and mouse events. I use evdev and pyudev packages to realize this function. I have my scripts mostly working, including keyboard and mouse event detection and plug-in detection. However, whenever I plug-out the mouse, many weird things happen and my script could not work properly. I have several confusions here.
(1) Whenever the mouse is plugged into the system, there are two files generated in /dev/input/ folder, including ./mouseX and ./eventX. I try to cat to see the output from both source and there are indeed differences, but I do not understand why linux will have ./mouseX even if ./eventX already exists?
(2) Whenever I unplug my mouse, the ./mouseX unplug event comes first, which I did not use in evdev, and this leads to the failure of the script because ./eventX(where I read the data in the script) is unplugged simultaneously but I could only detect ./eventX in the next round. I use a trick(variable i in my script) to bypass this issue, but even though I could successfully delete the mouse device, the select.select() begins endless input reading even though I did not type anything to the keyboard.
The script is listed below(modified based on answers from previous post), thanks beforehand for your attention!
#!/usr/bin/env python
import pyudev
from evdev import InputDevice, list_devices, categorize
from select import select
context = pyudev.Context()
monitor = pyudev.Monitor.from_netlink(context)
monitor.filter_by(subsystem='input')
monitor.start()
devices = map(InputDevice, list_devices())
dev_paths = []
finalizers = []
for dev in devices:
if "keyboard" in dev.name.lower():
dev_paths.append(dev.fn)
elif "mouse" in dev.name.lower():
dev_paths.append(dev.fn)
devices = map(InputDevice, dev_paths)
devices = {dev.fd : dev for dev in devices}
devices[monitor.fileno()] = monitor
count = 1
while True:
r, w, x = select(devices, [], [])
if monitor.fileno() in r:
r.remove(monitor.fileno())
for udev in iter(functools.partial(monitor.poll, 0), None):
# we're only interested in devices that have a device node
# (e.g. /dev/input/eventX)
if not udev.device_node:
break
# find the device we're interested in and add it to fds
for name in (i['NAME'] for i in udev.ancestors if 'NAME' in i):
# I used a virtual input device for this test - you
# should adapt this to your needs
if 'mouse' in name.lower() and 'event' in udev.device_node:
if udev.action == 'add':
print('Device added: %s' % udev)
dev = InputDevice(udev.device_node)
devices[dev.fd] = dev
break
if udev.action == 'remove':
print('Device removed: %s' % udev)
finalizers.append(udev.device_node)
break
for path in finalizers:
for dev in devices.keys():
if dev != monitor.fileno() and devices[dev].fn == path:
print "delete the device from list"
del devices[dev]
for i in r:
if i in devices.keys() and count != 0:
count = -1
for event in devices[i].read():
count = count + 1
print(categorize(event))
The difference between mouseX and eventX is, generally speaking, is eventX is the evdev device, whereas mouseX is the "traditional" device (which, for example, doesn't support various evdev ioctls.)
I don't know what's wrong with the code you posted, but here is a code snippet which does the right thing.
#!/usr/bin/env python
import pyudev
import evdev
import select
import sys
import functools
import errno
context = pyudev.Context()
monitor = pyudev.Monitor.from_netlink(context)
monitor.filter_by(subsystem='input')
# NB: Start monitoring BEFORE we query evdev initially, so that if
# there is a plugin after we evdev.list_devices() we'll pick it up
monitor.start()
# Modify this predicate function for whatever you want to match against
def pred(d):
return "keyboard" in d.name.lower() or "mouse" in d.name.lower()
# Populate the "active devices" map, mapping from /dev/input/eventXX to
# InputDevice
devices = {}
for d in map(evdev.InputDevice, evdev.list_devices()):
if pred(d):
print d
devices[d.fn] = d
# "Special" monitor device
devices['monitor'] = monitor
while True:
rs, _, _ = select.select(devices.values(), [], [])
# Unconditionally ping monitor; if this is spurious this
# will no-op because we pass a zero timeout. Note that
# it takes some time for udev events to get to us.
for udev in iter(functools.partial(monitor.poll, 0), None):
if not udev.device_node: break
if udev.action == 'add':
if udev.device_node not in devices:
print "Device added: %s" % udev
try:
devices[udev.device_node] = evdev.InputDevice(udev.device_node)
except IOError, e:
# udev reports MORE devices than are accessible from
# evdev; a simple way to check is see if the devinfo
# ioctl fails
if e.errno != errno.ENOTTY: raise
pass
elif udev.action == 'remove':
# NB: This code path isn't exercised very frequently,
# because select() will trigger a read immediately when file
# descriptor goes away, whereas the udev event takes some
# time to propagate to us.
if udev.device_node in devices:
print "Device removed (udev): %s" % devices[udev.device_node]
del devices[udev.device_node]
for r in rs:
# You can't read from a monitor
if r.fileno() == monitor.fileno(): continue
if r.fn not in devices: continue
# Select will immediately return an fd for read if it will
# ENODEV. So be sure to handle that.
try:
for event in r.read():
pass
print evdev.categorize(event)
except IOError, e:
if e.errno != errno.ENODEV: raise
print "Device removed: %s" % r
del devices[r.fn]

How to get linux screen title from command line

How can I fetch the title of a screen session from the command line?
I came up with a very small and simple python script with pexpect to do it.
It is handy in multiuser environments where some host is reserved and status is written to screen title by user.
It works for me, feel free to make it better.
In order to fetch specific session title, you need to modify the script and call for correct session.
If you run this through remote connection as local script (through SSH for example), remember to set export TERM=xterm before execution.
try:
import pexpect
import sys
child=pexpect.spawn('screen -x')
child.sendcontrol('a');
child.send('A');
i = child.expect('Set window.*')
child.sendcontrol('c');
child.sendcontrol('a');
child.send('d');
TITLE=str(child.after)
TITLE_P=TITLE.split('7m')
if str(TITLE_P[-1]) == '':
print 'Title not found'
else:
print str(TITLE_P[-1])
except:
print 'Could not check screen Title'

Categories