How can I pass an argument to a Python module while importing it?
For instance, while running a script from command line, I can do this:
python script.py [arg1] [arg2]
I want to do the same while I am importing a module in python
I have two modules, one.py and two.py
one.py:
name='TestTab'
import two [arg(which i want to be name variable)]
tweet = Tweet()
two.py:
import sqlalchemy
name= [received arg]
class Tweet():
__tabname__ = name
id = Column(String(255))
Basically, I want to create a new table every time I import two.py, and I want the name of the new table to be passed while importing.
That's not a feature of Python, and you're not using classes well by using class-level variables and no constructor. The way to approach this is to pass the parameter to the constructor of Tweet, and store the data as instance variables.
one.py
name='TestTab'
from two import Tweet
tweet = Tweet(whatever_name)
two.py
import sqlalchemy
class Tweet(object):
def __init__(self, name):
self.tabname = name
self.id = Column(String(255))
Not really pythonic but a possible simplest way is to expose your variable out
one.py
import two
two.name = "test"
tweet = two.Tweet()
two.py
import sqlalchemy
name = None
class Tweet():
__tabname__ = name
id = Column(String(255))
Related
Is it possible use a variable as a container for a Python module, and then adding another one to the same variable?
So for example, if I would have a Python file called general_config.py containing a general config of some kind:
class GeneralConfig:
attribute1 = "Some attribute"
attribute2 = "Some other attribute"
And if I would import this Python module as a variable containing a general config, I would do:
import general_config.py as Config
Then I can access its attributes by doing:
generalParameter = Config.GeneralConfig.attribute1
But what if I want to add some specific parameters to my config (say from specific_config.py), while keeping the general one as part of the entire config? So it would do something like that:
if someSpecificCondition:
Config += import specific_config.py
else:
Config += import other_config.py
While keeping the Config in the original scope? Thanks in advance.
If you want your general config to inherit your other configs for whatever reason, you could do something like this. But Tom's answer makes more sense, since there's no runtime class creation.
class BaseConfig:
att = "hello world"
def inherit_configs(some_condition):
if some_condition:
from config1 import Config1
class Config(BaseConfig, Config1):
pass
return Config
else:
from config2 import Config2
class Config(BaseConfig, Config2):
pass
return Config
config = inherit_configs(some_condition)()
I want to build a well-modularized python project, where all alternative modules should be registed and acessed via a function named xxx_builder.
Taking data class as an example:
register.py:
def register(key, module, module_dict):
"""Register and maintain the data classes
"""
if key in module_dict:
logger.warning(
'Key {} is already pre-defined, overwritten.'.format(key))
module_dict[key] = module
data_dict = {}
def register_data(key, module):
register(key, module, data_dict)
data.py:
from register import register_data
import ABCDEF
class MyData:
"""An alternative data class
"""
pass
def call_my_data(data_type):
if data_type == 'mydata'
return MyData
register_data('mydata', call_my_data)
builder.py:
import register
def get_data(type):
"""Obtain the corresponding data class
"""
for func in register.data_dict.values():
data = func(type)
if data is not None:
return data
main.py:
from data import MyData
from builder import get_data
if __name__ == '__main__':
data_type = 'mydata'
data = get_data(type=data_type)
My problem
In main.py, to register MyData class into register.data_dict before calling the function get_data, I need to import data.py in advance to execute register_data('mydata', call_my_data).
It's okay when the project is small, and all the data-related classes are placed according to some rules (e.g. all data-related class should be placed under the directory data) so that I can import them in advance.
However, this registeration mechanism means that all data-related classes will be imported, and I need to install all packages even if I won't use it actually. For example, when the indicator data_type in main.py is not mydata I still need to install ABCDEF package for the class MyData.
So is there any good idea to avoid importing all the packages?
Python's packaging tools come with a solution for this: entry points. There's even a tutorial about how to use entry points for plugins (which seems like what you're doing) (in conjunction with this Setuptools tutorial).
IOW, something like this (nb. untested), if you have a plugin package that has defined
[options.entry_points]
myapp.data_class =
someplugindata = my_plugin.data_classes:SomePluginData
in setup.cfg (or pypackage.toml or setup.py, with their respective syntaxes), you could register all of these plugin classes (here shown with an example with a locally registered class too).
from importlib.metadata import entry_points
data_class_registry = {}
def register(key):
def decorator(func):
data_class_registry[key] = func
return func
return decorator
#register("mydata")
class MyData:
...
def register_from_entrypoints():
for entrypoint in entry_points(group="myapp.data_class"):
register(entrypoint.name)(entrypoint.load())
def get_constructor(type):
return data_class_registry[type]
def main():
register_from_entrypoints()
get_constructor("mydata")(...)
get_constructor("someplugindata")(...)
I want to list variables "defined" in a module. And then I found there is no way to distinct variables defined in the module and variables imported from other modules. Is there any way to know if a variable is imported?
I KNOW inspect.getmembers and inspect.getmodule and dir but my concern is variable, not function or class definition.
AND I KNOW I COULD IMPORT MODULE RATHER THAN IMPORT VARIABLE FROM MODULE.
I just want to know is there a way or not :).
a.py, define a class
class A(object):
pass
b.py, define a instance using class A
from a import A
ins_b = A()
c.py, define another instance using class A and
from a import A
from b import ins_b
ins_c = A()
I want to list variables like this:
["b.ins_b", "c.ins_c"]
but actually I could do is :
{
<a.A instance at pos1>: ["b.ins_b", "c.ins_b"],
<a.A instance at pos2>: ["c.ins_c"],
}
OK. Thanks to #juanpa.arrivillaga I know it is impossible to do this.
And I just change the problem: how to know "the module which object is created" and "the attr name which the object is assigned".
I try to find something like "metaclass", maybe "metamodule" but I find it changes many behaviors which I do not need.
So according to "How to use inspect to get the caller's info from callee in Python?" and "Retrieve module object from stack frame", I do some trick to realize my idea.
import inspect
import re
attr_r = re.compile(u"\s*([^\s=]+)\s*=")
class A(object):
def __init__(self):
pre_frame = inspect.currentframe().f_back
frame_info = inspect.getframeinfo(pre_frame)
self.init_module_name = inspect.getmodule(pre_frame).__name__
self.init_attr_name = ""
if len(frame_info[3]) > 0:
line = frame_info[3][0]
m = attr_r.match(line)
if m:
self.init_attr_name = m.group(1)
the method to get attr name is trick but work for me.
# init_module_name == "a"
a = A()
print a.init_module_name, a.init_attr_name
# init_module_name == "a"
a = b = A()
print a.init_module_name, a.init_attr_name
# init_module_name == ""
a = \
A()
print a.init_module_name, a.init_attr_name
I was attempting to render a Jinja2 template while passing in a single parameter. This parameter is an instance of an object which has a method that references a second object. The object I'm passing into Jinja2 is stored in one module, while the referenced object is stored in a second module. The rendering takes place in a third module. The original code would error out when the first object's method references the second object (global name ... is not defined). This method works fine outside of Jinja2. Here's a simple example to set the scene...
The jinja2 rendering module looks like this:
from jinja2 import Template
from module1 import *
from module2 import *
def return_rendered():
otr = ObjectToRender()
otr.name = 'Just making the instance special!'
temp_str = open('template.html', 'r')
template = Template(temp_str.read())
temp_str.close()
return template.render(otr=otr)
and the template looks like this:
<p>Here is the output from a super cool method!<p>
{{ otr.get_a_cool_name() }}
The object to render:
# module1
class ObjectToRender(object):
def __init__(self):
self.name = ''
def get_a_cool_name(self):
rc = ReferencedClass() # fails here with "global name
# 'ReferencedClass' is not defined"
return rc.make_cool(self.name)
from module2 import *
and the referenced class:
# module2
from module1 import *
class ReferencedClass(object):
def __init__(self):
self.cool_str = 'SUPER COOL'
def make_cool(self, in_str):
return in_str + self.cool_str
You'll notice I've imported modules 1 and 2 "into each other". It's obviously not necessary here, but in my use case it is. Anyway, I was able to get this working by importing the second class again, just before the ReferencedClass is used. It looks like this:
# module1
class ObjectToRender(object):
def __init__(self):
self.name = ''
def get_a_cool_name(self):
from module2 import ReferencedClass
rc = ReferencedClass() # it works!
return rc.make_cool(self.name)
from module2 import *
So, I got it working without really understanding why it didn't work in the first place... Classic. Does anyone know why I'm having to import this class a second time?
In my problem I have a python code that is being started by a user, like:
# file main.py
import sys
import mymodule
config = sys.argv[1]
which imports another module containing functions, classes etc. like
# module.py
def check_config():
# do something with the content of 'config'
class Module(object):
# does something with the content of 'config'
How can I access the value of 'config' from within module.py? Should I use a 'global' variable here? Or is there a more sophisticated, pythonic way to solve this problem?
Also, I do not want to define an argument 'config' to each function and class I use in other modules...
Further remark: main.py imports other modules, not the other way around...
Instead of trying to wrangle global into performing this you should pass config as a parameter.
file main.py
import sys
import mymodule
config = sys.argv[1]
checked = mymodule.check_config(config)
mod = mymodule.Module(config)
module.py
def check_config(config):
# do something with the content of 'config'
class Module(object):
# does something with the content of 'config'
def __init__(self, config):
# initialise with config
Always avoid usingglobal when you can. If you need to modify config just have a module function return it.
config = change_config(config)
module.py
def change_config(config):
...
return config
However, an alternative method is to define a value within module.py which will store this information that holds nothing by default. Then as soon as file main.py has imported module.py and the config data is ready, you could assign the data to module.py's config name. Like this:
file main.py
import sys
import mymodule
config = sys.argv[1]
mymodule.config = config
mymodule.test_config()
mymodule.check_config()
mymodule.Module()
module.py
config = None
def test_config():
print config
# this will refer to the value supplied from file main.py
Note however, that the values in the module and main file will not be joined. If you reassign config in file main.py for any reason you have to pass that value to the module again. However if you pass a mutable value like a dict or list then you can modify it in file main.py and the values will be shared.
I don't recommend using a global variable, but here's the design you should use if you do. config needs to be defined in mymodule; after you import the module, you can set the value of mymodule.config the way you are currently setting config.
# file main.py
import sys
import mymodule
mymodule.config = sys.argv[1]
# module.py
# The exact value doesn't matter, as long as we create the name.
# None is good as it conveys the lack of a value; it's part of your
# module's contract, presumably, that a proper value must be assigned
# before you can use the rest of the module.
config = None
def check_config():
# do something with the content of 'config'
class Module(object):
# does something with the content of 'config'
A global variable is almost never the answer. Just allow the functions and classes in your "library" (module.py or mymodule.py, you seem to use both) to accept arguments. So:
mymodule.py
def check_config(configuration):
pass
class Module(object):
def __init__(self, configuration):
self.config = configuration
class ConfigError(Exception):
pass
Then when you want to use them in your "application" code:
main.py
import sys
import mymodule
config = sys.argv[1]
if mymodule.check_config(config):
myobject = mymodule.Module(config)
else:
raise mymodule.ConfigError('Unrecognized configuration format.')
Could you describe that you app should to do? Because now it's not clear, why you want it.
Maybe environment variable could help you?
Btw, you can read config file in one place (module), and import all stuff you need from it.
config.py
import os
if os.environ['sys'] == 'load_1':
import load_1 as load
i = 12
else:
import load_2 as load
i = 13
main.py
import config
config.load("some_data")
print config.i