Include variables in template context on every page with Bottle.py - python

Is there a bottle.py equivalent of context processors that you get in Flask?

If you're using vanilla Bottle with SimpleTemplate, there is a solution I've stumbled upon.
For my site, I needed access to some functions in every template, app.get_url being obviously one of them. This worked for me:
# after app creation, but before the views
SimpleTemplate.defaults["get_url"] = app.get_url
SimpleTemplate.defaults["url"] = lambda: request.url
SimpleTemplate.defaults["fullpath"] = lambda: request.fullpath
SimpleTemplate.defaults["sorted"] = sorted
This works as of Bottle 0.9, I didn't test on more recent versions of the framework.
This behavior is undocumented, but Marcel Hellkamp explained it in this thread. In there, other solutions are also mentioned:
Pass over the globals in _vars or a similar template arg.
Create a decorator to supply the defaults.
Also, in Bottle 0.10, new functions related to the problem were introduced in the SimpleTemplate template namespace: defined, get, and setdefault

Using the previous answer from Helgi, I use this hook to make a context processor like (bottle 0.12.x) :
import bottle
#bottle.hook('before_request')
def _context_processor():
bottle.SimpleTemplate.defaults['foo'] = 'F00'
bottle.SimpleTemplate.defaults['bar'] = 'B#R'

Note: this same solution can be used with the other template engines. The technique is exactly the same, but you use BaseTemplate (it works for all template classes) or the class for the engine you want to use.

Related

Mako: render with predefined/default items in Context?

I'm looking for an idiom for setting some common item definitions so that any time I call render() on a mako template, those items will be added to the parameters available in the template without having to include them in the parameters to render() each time.
The example at http://docs.makotemplates.org/en/latest/usage.html suggests that the place I should be looking is in some way of either setting some master Context definitions or something, or perhaps a way of merging two contexts:
from mako.template import Template
from mako.runtime import Context
from StringIO import StringIO
mytemplate = Template("hello, ${name}!")
buf = StringIO()
ctx = Context(buf, name="jack")
mytemplate.render_context(ctx)
print(buf.getvalue())
I can't find anything explicitly showing an example of doing this, and poking around in dir(Context) isn't making anything come to mind. Is this a simple thing to do and I'm just overlooking the obvious? Or is there a standard idiom for this?
Thanks in advance!
Update: I suppose one approach is to explicitly append **kwargs to each call to render(), and that's not bad, as it's explicit:
template = self.template_lookup.get_template("index.mako.html")
return template.render(var1=val1, var2=val2, **common_vars)
Still curious if there's a way to "fully predefine" such items.

Sphinx revealing my (mailgun) password

I have a simple function
import config
def send_message(mailgunkey=config.MAILGUNKEY):
"""
send an email
"""
It relies on a variable defined in my config.py file. I read the variables from local files on all my machines as I don't want to have my keys etc. in any repository. However, I recently got into the habit of using Sphinx. When generating the html docs the expression config.MAILGUNKEY is getting evaluated and the actual key is revealed in the html file. Is there an option to stop this kind of undesired action?
Consider using this approach:
import config
def send_message(mailgunkey=None):
"""
send an email
"""
if mailgunkey is None:
mailgunkey = config.MAILGUNKEY
In general, this approach gives you some important advantages:
lets your users pass None as the default;
allows changes to config.MAILGUNKEY even if your module has already been imported;
solves the problem of mutable default arguments (not your case, but still it's something to be aware of).
The second point is, in my opinion, something very important, as I would be very surprised to see that changes to a configuration variable at runtime have no effects.
Another option would be to mock the module that has your secrets.
This avoids needing to change your code to generate documentation.
Assuming you are using autodoc; add the below to your conf.py:
autodoc_mock_imports = ["config","secrets",]
https://www.sphinx-doc.org/en/master/usage/extensions/autodoc.html?highlight=autodoc_mock_imports%20#confval-autodoc_mock_imports
The autodoc_preserve_defaults configuration option was added in Sphinx 4.0.
The problem is solved by setting this option to True in conf.py. Default argument values of functions will not be evaluated and shown in the generated output.

Can I replace an attribute with a lambda WITHOUT changing access syntax?

I have a boolean that is used all over a system I've just joined (it's Django's settings.DEBUG, but that's not really important, since this would be handy for testing, as well.)
I want to prevent non-django use of this attribute. Developers using my system should get an exception, telling them to use a different attribute:
settings.DEBUG = lambda: return_bool_or_throw_exception_if_caller_forbidden()
The trouble is, switching to a lambda requires that accessors change:
#instead of:
if settings.DEBUG:
#now:
if settings.DEBUG():
But this would require changing all the reads of DEBUG in Django code, which is unacceptable in my situation. Can I deliver a lambda or a function with no arguments in such a way that consumers can access the thing without function call semantics?
You could monkey patch the settings class and set DEBUG to a descriptor:
def DEBUG(self):
return return_bool_or_throw_exception_if_caller_forbidden()
settings.__class__.DEBUG = property(DEBUG)

AssertionError, altough the expected call looks same as actual call

I made a command in django which calls a function.
That function does a django orm call:
def get_notes():
notes = Note.objects.filter(number=2, new=1)
return [x.note for x in notes]
I want to patch the actual lookup:
#mock.patch('Note.objects.filter', autospec=True)
def test_get_all_notes(self, notes_mock):
get_notes()
notes_mock.assert_called_once_with(number=2, new=1)
I get the following assertion error:
AssertionError: Expected call: filter(number=2, new=1)
Actual call: filter(number=2, new=1)
I search on google and stackoverflow for hours, but I still haven't a clue.
Can anyone point me in the right direction, I think it might be an obvious mistake I'm making...
AFAIK you can't use patch() like this. Patch target should be a string in the form package.module.ClassName. I don't know much about django but I suppose Note is a class so Note.objects.filter is not something you can import and hence use in patch(). Also I don't think patch() can handle attributes. Actually I don't quite understand why the patch works at all.
Try using patch.object() which is specifically designed to patch class attributes. It implies Note is already imported in your test module.
#mock.patch.object(Note, 'objects')
def test_get_all_notes(self, objects_mock):
get_notes()
objects_mock.filter.assert_called_once_with(number=2, new=1)
I've removed autospec because I'm not sure it will work correctly in this case. You can try putting it back if it works.
Another option might be to use patch() on whatever you get with type(Note.objects) (probably some django class).
As I've said I don't know much about django so I'm not sure if these things work.

Django: Streaming dynamically generated XML output through an HttpResponse

recently I wanted to return through a Django view a dynamically generated XML tree. The module I use for XML manipulation is the usual cElementTree.
I think I tackled what I wanted by doing the following:
def view1(request):
resp = HttpResponse(g())
return resp
def g():
root = Element("ist")
list_stamp = SubElement(root, "list_timestamp")
list_creation = str(datetime.now())
for i in range(1,1000000):
root.text = str(i)
yield cET.tostring(root)
Is something like this a good idea ? Do I miss something ?
About middlewares "breaking" streaming:
CommonMiddleware will try to consume the whole iterator if you set USE_ETAGS = True in settings. But in modern Django (1.1) there's a better way to do conditional get than CommonMiddleware + ConditionalGetMiddleware -- condition decorator. Use that and your streaming will stream okay :-)
Another thing that will try to consume the iterator is GzipMiddleware. If you want to use it you can avoid gzipping your streaming responses by turning it into a decorator and applying to individual views instead of globally.
Does it work? If it doesn't work, what error does it throw?
If you're building a full-blown API for a django site, take a look at django-piston. It takes care of a lot of the busywork related to that.
http://bitbucket.org/jespern/django-piston/wiki/Home
Yes, it's perfectly legitimate to return an iterator in an HttpResponse. As you've discovered, that allows you to stream content to the client.
Yes. That's THE WAY you do it on Django.

Categories

Resources