How does django convert string to modules - django

I am trying to understand an other magic thing about django: it can convert strings to modules.
In settings.py, INSTALLED_APPS is declared like that:
INSTALLED_APPS = (
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
)
All it contains is strings. But django will convert those strings to modules and import them later.
I want to do be able to do the same thing. but i don't know how.
I have a dictionary of renderer dispatcher in settings.py:
RESOUCE_RENDERER = {
'video': 'video_player',
'audio': 'audio_player',
}
I want to use it later like this: RESOURCE_RENDERER['video'](MyVideo).
I cannot assign directly the function name(eg video_player) because it lives in a module that needs settings.py.

Since Django 1.7 there is a simple function for this. For example:
from django.utils.module_loading import import_string
my_module = import_string('path.to.my_module')
You can also get classes from the module:
MyClass = import_string('path.to.my_module.MyClass')

Take a look in django.conf.__init__.py, but basically it uses importlib like so:
try:
mod = importlib.import_module(self.SETTINGS_MODULE)
except ImportError, e:
raise ImportError("Could not import settings '%s'
(Is it on sys.path? Does it have syntax errors?):
%s" % (self.SETTINGS_MODULE, e))
# Settings that should be converted into tuples if they're mistakenly entered
# as strings.
tuple_settings = ("INSTALLED_APPS", "TEMPLATE_DIRS")
Edit: At the request of the OP I've expanded the example and contributed some more below.
Now, suppose you had a list of functions in this module, defined in for example FUNCTIONS TO CALL, a list of functions. Then, you could call each like this:
ARGUMENTS = '()'
for FUNCTION in FUNCTIONS_TO_CALL:
function_string = FUNCTION + ARGUMENTS
exec(function_string)
This assumes each function has the same set of defined arguments. You could use an if statement to detect the function name listed by the user and supply custom arguments depending on what this is. You could also evaluate from reading the python file what the arguments should be.
You could also check the module object to (I assume this is possible, I don't know) see if that function exists before calling exec() or eval(). I don't know, again, if one can evaluate from the function object what arguments it takes. I suspect so, but this is a separate (possibly already answered?) question.

Related

Python argparse argument that is python keyword

I want to have a python command line argument --lambda, but I can't access it as lambda is a python keyword.
import argparse
p = argparse.ArgumentParser()
p.add_argument('--lambda')
args = p.parse_args()
print args.lambda
I get:
print args.lambda
^
SyntaxError: invalid syntax
How can I do this?
You can add a different name for the attribute with dest e.g.
import argparse
p = argparse.ArgumentParser()
p.add_argument('--lambda', dest='llambda')
args = p.parse_args()
print args.llambda
argparse uses hasattr and getattr to set values in the Namespace. This allows you to use flags/dest that are not valid in the args.dest syntax. Here the problem is with a restricted key word. It could also be a string with special characters. So getattr(args, 'lambda') should work.
vars(args) creates a dictionary, allowing you to use vars(args)['lambda'].
But changing the dest is a cleaner solution. That's part of why that parameter is allowed.
(For a positional argument, choose a valid dest right away.)

Manually pass commands into argparse? | Python 2.7

I am making a terminal game using Python's wonderful Cmd library. But i was curious if i could somehow put argparse code into it. Like use argparse to handle the 'args' from my cmd.Cmd() class.
To do this, i was really hoping that argparse had a way to manually pass args into it. I skimmed over the docs, but didn't notice anything like that.
parse_args() takes an optional argument args with a list (or tuple) of to parse. parse_args() (without arguments) is equivalent to parse_args(sys.argv[1:]):
In a script, parse_args() will typically be called with no arguments, and the ArgumentParser will automatically determine the command-line arguments from sys.argv.
If you do not have a tuple, but a single string, shell-like argument splitting can be accomplished using shlex.split()
>>> shlex.split('"A" B C\\ D')
['A', 'B', 'C D']
Note that argparse will print usage and help messages as well as exit() on fatal errors. You can override .error() to handle errors yourself:
class ArgumentParserNoExit(argparse.ArgumentParser):
def error(self, message):
raise ValueError(message) # or whatever you like
You could also try namedtuple to manually provide the input arguments,
from collections import namedtuple
ManualInput = namedtuple("ManualInput", ["arg1", "arg2"])
args = ManualInput(1, 4)
you will get
In [1]: print(args.arg2)
Out[1]: 4

Surprising behaviour using TemplateEngine with variable "URL" interpreted as class

Given the following Groovy code:
def engine = new SimpleTemplateEngine()
def propMap = [ URL: "http://stackoverflow.com",URL2: "http://stackoverflow.com"]
def result = engine.createTemplate('''
${URL}
${URL2}
''').make(propMap) as String
println(java.net.URL)
the output is
class java.net.URL
http://stackoverflow.com
Somehow the URL ends up being interpreted as class java.net.URL (which Groovy seems to be auto-importing), but why? And can a variable named URL used in this context?
Groovy is making several default imports, which also includes java.net. Import java.net.URL apparently shadows your local variable.
You could use this to explicitly tell Groovy to use your variable instead of java.net.URL.
${this.URL}
${URL2}
I also tried to use alias for import like this:
import java.net.URL as JavaURL
but it didn't really help, because both implicit (URL) and explicit (JavaURL) imports were used.

How to return a lazy translation object with placeholders?

In my Django v1.6.5 project running on Python v2.7.x, I have a Model that returns its configuration as a string. I need the returned string to be a gettext_lazy object, so I can evaluate it in any language required later.
from __future__ import unicode_literals
from django.utils.translation import ugettext_lazy as _, string_concat
...
class MyModel(models.Model):
key = models.CharField(...)
value = models.CharField(...)
#property
def config_str(self):
return _('some configuration')
This seems to work fine in these scenarios:
Static string: (see above) - works!
String concatenation: return string_concat(self.key, _(' equals '), self.value) - works!
What is not working, is using gettext_lazy with placeholders, a la:
return _('“%(key)s” equals “%(value)s”' % {key: self.key, value: self.value})
or using the .format() mechanism:
return _('“{key}” equals “{value}”').format(key=self.key, value=self.value)
When I do this, my .po file does contain:
#, python-format
msgid "“%(key)s” equals “%(value)s”" or
msgid "«{key}» equals «{value}»"
but even when I populate this Eg.:
msgstr "«%(key)s» est égal à «%(value)s»" or
msgstr "«{key}» est égal à «{value}»"
and I run compilemessages, the translation seems to be ignored. When I translate the promise returned by the model instance, I always get an EN string with the placeholders filled E.g., '“foo” equals “bar”'. Note, I get an EN string even when the first calling context is FR (for example). This tells me that the translations just aren't even occurring. It is my theory that by the time I eval the lazy object, gettext is looking for the literal string "“foo” equals “bar”" (for example) in the translation catalog rather than something with placeholders and named values.
With this in mind, I've also tried wrapping the whole format() in the lazy object like this:
return _('“{key}” equals “{value}”'.format(key=self.key, value=self.value))
But it seems to have made zero difference. =/
I can get by with string_concat() for now, but sometimes, the placeholders will need to be moved around in some translations, so I'd like to figure this out.
I'm beginning to think that one simply cannot use placeholders with gettext_lazy.
NOTE: I have reviewed django: Translation with variables inside, but a) that has no accepted answer and b) he's using gettext, not gettext_lazy.
OK, the solution here is to provide an extra layer of laziness (Thanks, Django core dev: Florian Apolloner AKA “apollo13”).
Here's my modified function that WORKS:
from django.utils import six
from django.utils.functional import lazy
class MyModel(models.Model):
key = models.CharField(...)
value = models.CharField(...)
#property
def configuration_string(self):
def wrapper():
return _('“{key}” equals “{value}”').format(
key=self.key,
value=self.value
)
return lazy(
wrapper,
six.text_type
)
The only thing is, where I use this, I must remember to eval the wrapper function as follows:
from django.utils.encoding import force_text
config = my_model_instance.configuration_string
# NOTE: Evaluate the lazy function wrapper inside the force_text()
config_str = force_text(config())
Now, in my case, I need to support cases where 3rd party devs write the function configuration_string returning either the lazy function wrapper, a lazily evaluated translation string or just a regular string, so I use:
import types
from django.utils.encoding import force_text
from django.functional import Promise
config = my_model_instance.configuration_string
if isinstance(config, types.FunctionType):
config_str = force_text(config())
elif isinstance(config, Promise):
config_str = force_text(config)
else:
config_str = config
Thanks again to Apollo13 for guidance!
I had a very similar problem and found that using gettext_noop instead of gettext_lazy worked for me available since Django 1.11.

path apps in django

I wanna get absolute path all installed_apps in "setting.py" .
app_list = [ app for app in Myproject.settings.INSTALLED_APPS ]
I list of application but how i can get absolute path all of them.
Thank you.
It's not really possible to do what you want. I mean you can get almost there, but there's no real functionality for this, and in particular, Python doesn't distinguish between classes, methods, and variables. They all count as attributes of the module.
First, INSTALLED_APPS is a tuple of strings. So, in order to get any useful information, you're going to have load them as modules:
for app in settings.INSTALLED_APPS:
module = __import__(app)
Then, once you have the actual module, you can call dir on it to get a list of its attributes:
for app in settings.INSTALLED_APPS:
module = __import__(app)
print dir(module)
And, that's about as far as you can go. It's going to output everything set in the module, not just classes. From here, about the only recourse I can think of to weed out everything but classes is to assume that naming conventions were followed and look for items that start with a capital letter. That's not exactly scientific, but that's all you got.
Today I solved my problem. I write this code and its just working. For limited name class I find name of class that inherent from "models.Model" . you can change it and enjoy that.also this code find files in depth 1 of modules. it can change.
app_list = [app for app in training.settings.INSTALLED_APPS if "task" in app]
for module in app_list:
module1 = __import__(module)
temp = module1.__path__
files_path = [temp[0] + os.sep + files_name for files_name in os.listdir(temp[0]) if
os.path.splitext(files_name)[1] == ".py"]
p = re.compile(r'class\s*\w*\s*\(models.Model\):')
for file in files_path:
infile = open(file)
text = infile.read()
all_class = p.findall(text)
print [class_name[6:][:-15] for class_name in all_class]