Say I have a variable that helps with a network connection (eg: API access token) that I want to use in a module that I'm importing (for use in expanding on existing functions), is there a way to pass that variable to the imported script without adding a new class or method to initialize it?
eg:
Script one (performer.py):
import telepot
import botActions # Possibly adding an argument here?
botActions.sendMessage("locationID", "message")
accessToken = "SAMPLE"
Script two (botActions.py):
import botApiWrapper
def sendMessage(locationID, text):
bot.sendMessage(locationID, text)
print("Message sent to %g: %t".format(g=locationID, t=text))
bot = botApiWrapper.Bot(sys.argv[0])
So is there a way to pass the variable to the second script from the first one, or would I have to define an initializing function that I call after importing the file?
The canonical way to do something like this is to define an initialization function from the other file. Instead of bot = botApiWrapper.Bot(sys.argv[0]), try something like
def newbot(arg):
bot = botApiWrapper.Bot(arg)
return bot
and then call that function from your other module.
If you need state to operate, define a class.
class Bot(object):
def __init__(self, arg):
self.arg = arg
def sendMessage(self, locationId, text):
print "Using arg %s to send message to location %s with text %s" % \
(self.arg, locationId, text)
...thereafter letting you initialize as many bots as you like:
import botApiWrapper
botA = botApiWrapper.Bot("A")
botA.sendMessage("foo", "bar")
botB = botApiWrapper.Bot("B")
botB.sendMessage("baz", "qux")
Related
I've been trying to understand COM libraries but I'm still confused. If I want to make a python object com visible, the only instructions I can find are to make a python script that sets up a COM server which is invoked and used to generate class instances by name. IIUC, this is made possible by permanently adding some information to the registry that links a CLSID to the path of my server.py file; here's a minimum example:
class HelloWorld:
# pythoncom.CreateGuid()
_reg_clsid_ = "{7CC9F362-486D-11D1-BB48-0000E838A65F}"
_reg_desc_ = "Python Test COM Server"
_reg_progid_ = "PythonTestServer.HelloWorld"
_public_methods_ = ["Hello"]
_public_attrs_ = ["softspace", "noCalls"]
_readonly_attrs_ = ["noCalls"]
def __init__(self):
self.softspace = 1
self.noCalls = 0
def Hello(self, who):
self.noCalls = self.noCalls + 1
# insert "softspace" number of spaces
return "Hello" + " " * self.softspace + str(who)
if __name__ == "__main__": #run once to register the COM class
import win32com.server.register
win32com.server.register.UseCommandLine(HelloWorld) #this is what I want to avoid
Called like:
Dim a as Object = CreateObject("PythonTestServer.HelloWorld") 'late binding
a.softSpace = 10
?a.Hello("World") 'prints "Hello World"
However I'm sure in the past I've downloaded some file.dll that I can just add as a reference to my COM client project (VBA) and I never call --register/regsrvr/etc. I assume the dll contains all the information needed to modify and revert changes to the registry at runtime. I can use Early or Late binding to create class instances. I even get intellisense if the referenced dll contains a type library.
The latter method feels much simpler and more portable. Is there a way to emulate this in python?
i have this code in a python file:
from dec import my_decorator
import asyncio
#my_decorator
async def simple_method(bar): # , x, plc_name, var_name):
print("Henlo from simple_method\npartent:{}".format(parent))
return
#my_decorator
async def other_simple_meth(bar, value):
print("Henlo from other_simple_meth:\t Val:{}".format(value))
return
async def main():
print("Start Module-Export")
open('module_functions.py', 'a').close()
# Write all decorated functions to modue_functions.py
print("Functions in module_functions.py exported")
while True:
asyncio.sleep(2)
print("z...z...Z...")
My goal is to write all decorated functions (inc. the import dependencies) into a second module file (here "module_functions.py"). My 'module_functions.py' file should look like this:
from dec import my_decorator
import asyncio
#my_decorator
async def simple_method(bar): # , x, plc_name, var_name):
print("Henlo from simple_method\npartent:{}".format(parent))
return
#my_decorator
async def other_simple_meth(bar, value):
print("Henlo from other_simple_meth:\t Val:{}".format(value))
return
I know how to get references and names of a function, but not how to "copy/paste" the functioncode (incl. decorator and all dependencies) into a seperated file. Is this even possible?
EDIT: I know that pickle and dill exist, but this may not fullfill the goal. The problem is, that someone else may not know the order of the dumped file and loading them back may/will cause problem. As well it seems to be not possible to edit such loaded functions again.
I found a (not ideal, but ok) solution for my problems.
I) Find and write functions, coroutines etc. into a file (works):
Like #MisterMiyagi suspected, is the inspect module a good way to go. For the common stuff, it is possible with inspect.getsource() to get the code and write them into a file:
# List of wanted stuff
func_list = [simple_method, meth_with_input, meth_with_input_and_output, func_myself]
with open('module_functions.py', 'a') as module_file:
for func in func_list:
try:
module_file.write(inspect.getsource(func))
module_file.write("\n")
except:
print("Error :( ")
II) But what about decorated stuff(seems to work)?
I) will not work for decorated stuff, it is just ignored without throwing an exception. What seems to be used is from functools import wraps.
In many examples the #wraps decorator is added into the decorator class. This was not possible for me, but there is a good workaround:
#wraps(lambda: simple_method) #<---add wraps-decorator here
#my_decorator
async def simple_method(parent): # , x, plc_name, var_name):
print("Henlo from simple_method\npartent:{}".format(parent))
return
Wraps can be placed above the original decorated method/class/function and it seems to behave like I want. Now we can add simple_methodinto the func_listof I).
III) What about the imports?
Well it seems to be quite tricky/impossible to actually read the dependencies of a function. My workaround is to drop all wanted imports into a class (sigh). This class can be throw into the func_listof I) and is written into the file.
EDIT:
There is a cleaner way, which may works, after some modification, with I) and II) as well. The magic module is ast.
I have overwritten following:
class ImportVisitor(ast.NodeVisitor):
def __init__(self, target):
super().__init__()
self.file_target = target
"pick these special nodes via overwriting: visit_classname." \
"classnames are listed in https://docs.python.org/3.6/library/ast.html#abstract-grammar"
def visit_Import(self, node):
"Overwrite func!"
"Write all statements just with import like - import ast into file_target"
str = 'import '+', '.join(alias.name for alias in node.names)
self.file_target.write(str+"\n")
def visit_ImportFrom(self, node):
"Overwrite func!"
"Write all statements with from ... import (like - from os.path import basename) into file_tagrget"
str = 'from '+ node.module+ ' import '+', '.join(alias.name for alias in node.names)
self.file_target.write(str+"\n")
Now I can parse my own script name and fill the module_file with the imports and from...imports it will find while visiting all nodes in this tree:
with open('module_functions.py', 'a') as module_file:
with open(basename(__file__), "rb") as f:
tree = ast.parse(f.read(), basename(__file__))
visitor = ImportVisitor(module_file)
visitor.visit(tree)
module_file.write("\n\n")
This is an ugly, high maintenance factory. I really just need a way to use the string to instantiate an object with a name that matches the string. I think metaclass is the answer but I can't figure out how to apply it:
from commands.shVersionCmd import shVersionCmd
from commands.shVRFCmd import shVRFCmd
def CommandFactory(commandnode):
if commandnode.attrib['name'] == 'shVersionCmd': return shVersionCmd(commandnode)
if commandnode.attrib['name'] == 'shVRFCmd': return shVRFCmd(commandnode)
You can look up global names with the globals() function, which returns a dict:
from commands.shVersionCmd import shVersionCmd
from commands.shVRFCmd import shVRFCmd
# An explicit list of allowed commands to prevent malicious activity.
commands = ['shVersionCmd', 'shVRFCmd']
def CommandFactory(commandnode):
cmd = commandnode.attrib['name']
if cmd in commands:
fn = globals()[cmd]
fn(commandnode)
This answer How to make an anonymous function in Python without Christening it? discusses how to cleanly call blocks of code based on a key
eval is your friend:
from commands import *
def CommandFactory(commandnode):
name=commandnode.attrib['name']
assert name in ( "shVersionCmd", "shVRFCmd" ), "illegal command"
return eval(name+"."+name)(commandnode)
Note that if you are sure that name will never contain any illegal commands, you could remove the assert and turn the function into a no-maintenance-delight. In case of doubt, leave it in and maintain the list in a single place.
My personal preference would be to turn the dependencies between the factory and the command implementations around, so that each command registers itself with the factory.
Example implementation:
File commands/__init__.py:
import pkgutil
import commands
_commands = {}
def command(commandCls):
_commands[commandCls.__name__] = commandCls
return commandCls
def CommandFactory(commandnode):
name = commandnode.attrib['name']
if name in _commands.keys():
return _commands[name](commandnode)
# Load all commands
for loader, module_name, is_pkg in pkgutil.walk_packages(commands.__path__):
if module_name!=__name__:
module = loader.find_module(module_name).load_module(module_name)
File commands/mycommand.py:
from commands import command
#command
class MyCommand(object):
def __init__(self, commandnode):
pass
Small test:
from commands import CommandFactory
# Stub node implementation
class Node(object):
def __init__(self, name):
self.attrib = { "name": name }
if __name__=='__main__':
cmd = CommandFactory(Node("MyCommand"))
assert cmd.__class__.__name__=="MyCommand", "New command is instance of MyCommand"
cmd = CommandFactory(Node("UnknownCommand"))
assert cmd is None, "Returns None for unknown command type"
How can I create an alias for a command in a line-oriented command interpreter implemented using the cmd module?
To create a command, I must implement the do_cmd method. But I have commands with long names (like constraint) and I want to provide aliases (in fact, shortcuts) for these commands (like co). How can I do that?
One possibility that came to my mind is to implement the do_alias (like do_co) method and just calling do_cmd (do_constraint) in this method. But this brings me new commands in the help of the CLI.
Is there any other way to achieve this? Or may be is there a way to hide commands from the help output?
The following solution makes aliased commands share a single help message. It lets you keep all of your aliases in a single easy to edit place, while making documentation much easier. It checks user input against an alias dictionary with function values and overrides both the default() (See sloth & brian) and do_help() methods.
Here I've made aliases 'c' and 'con' execute do_constraint(), 'q' invoke do_quit(), and 'h' invoke do_help(). The bonus of this solution is that 'h q' and 'help quit' print the same message. Documentation for several aliased commands can maintained in a single docstring.
import cmd
class prompt(cmd.Cmd):
def __init__(self):
cmd.Cmd.__init__(self)
self.aliases = { 'c' : self.do_constraint ,
'con' : self.do_constraint ,
'q' : self.do_quit ,
'h' : self.do_help }
def do_constraint(self, arg):
'''Constrain things.'''
print('Constraint complete.')
def do_quit(self, arg):
'''Exit the program.'''
return True
def do_help(self, arg):
'''List available commands.'''
if arg in self.aliases:
arg = self.aliases[arg].__name__[3:]
cmd.Cmd.do_help(self, arg)
def default(self, line):
cmd, arg, line = self.parseline(line)
if cmd in self.aliases:
self.aliases[cmd](arg)
else:
print("*** Unknown syntax: %s" % line)
You can overwrite the default method and search for a suitable command handler (as already suggested by Brian):
import cmd
class WithAliasCmd(cmd.Cmd):
def default(self, line):
cmd, arg, line = self.parseline(line)
func = [getattr(self, n) for n in self.get_names() if n.startswith('do_' + cmd)]
if func: # maybe check if exactly one or more elements, and tell the user
func[0](arg)
The docs mention a default method, which you can override to handle any unknown command. Code it to prefix scan a list of commands and invoke them as you suggest for do_alias.
I'm trying to find a nice way to read a log file in real time using python. I'd like to process lines from a log file one at a time as it is written. Somehow I need to keep trying to read the file until it is created and then continue to process lines until I terminate the process. Is there an appropriate way to do this? Thanks.
Take a look at this PDF starting at page 38, ~slide I-77 and you'll find all the info you need. Of course the rest of the slides are amazing, too, but those specifically deal with your issue:
import time
def follow(thefile):
thefile.seek(0,2) # Go to the end of the file
while True:
line = thefile.readline()
if not line:
time.sleep(0.1) # Sleep briefly
continue
yield line
You could try with something like this:
import time
while 1:
where = file.tell()
line = file.readline()
if not line:
time.sleep(1)
file.seek(where)
else:
print line, # already has newline
Example was extracted from here.
As this is Python and logging tagged, there is another possibility to do this.
I assume this is based on a Python logger, logging.Handler based.
You can just create a class that gets the (named) logger instance and overwrite the emit function to put it onto a GUI (if you need console just add a console handler to the file handler)
Example:
import logging
class log_viewer(logging.Handler):
""" Class to redistribute python logging data """
# have a class member to store the existing logger
logger_instance = logging.getLogger("SomeNameOfYourExistingLogger")
def __init__(self, *args, **kwargs):
# Initialize the Handler
logging.Handler.__init__(self, *args)
# optional take format
# setFormatter function is derived from logging.Handler
for key, value in kwargs.items():
if "{}".format(key) == "format":
self.setFormatter(value)
# make the logger send data to this class
self.logger_instance.addHandler(self)
def emit(self, record):
""" Overload of logging.Handler method """
record = self.format(record)
# ---------------------------------------
# Now you can send it to a GUI or similar
# "Do work" starts here.
# ---------------------------------------
# just as an example what e.g. a console
# handler would do:
print(record)
I am currently using similar code to add a TkinterTreectrl.Multilistbox for viewing logger output at runtime.
Off-Side: The logger only gets data as soon as it is initialized, so if you want to have all your data available, you need to initialize it at the very beginning. (I know this is what is expected, but I think it is worth being mentioned.)
Maybe you could do a system call to
tail -f
using os.system()