I'm trying to write a unit test for an old pylons 0.9.7 application.
The issue we have is that it's very easy to accidentally hard-code URL
paths in our jinja2 templates, which works fine until someone hosts
our application at a different prefix (i.e.- hosts it at
http://localhost/foo/ instead of just http://localhost/). I'm
doing this using the default "functional test" setup that paste
created for me. I query every controller action, and pass in a custom
SCRIPT_NAME like so:
response = self.app.get('/some/url/path',
extra_environ={'SCRIPT_NAME' : '/custom_prefix'})
I then use beautifulsoup to parse the document, iterating over all the
tags that have an href attribute or a src attribute, and ensure
that it starts with '/custom_prefix'.
Here's where things get odd: When we pass an absolute path in to
pylons.url (which is actually a routes.util.URLGenerator)in our templates like this:
{{ h.stylesheet_link(h.url('/css/style.css')) }}
...it works perfectly. However, when we call pylons.url with keyword
arguments like this:
{{ h.link_to('Home', h.url(controller='person', action='home')) }}
...the prefix is not inserted. However, the url() function works
correctly when running this correctly (i.e.- using mod_wsgi or
pastedeploy) with a non-empty SCRIPT_NAME.
I guess that I'm missing a critical step, but I can't think what it is.
Related
Well, I haven't been getting some answers or commentary partly because the codes in the original content below is so restricted to their own small contexts, so instead of that, I wanted to share the whole codebase with you (don't worry, I will permalink the selected lines) because I intend to open the source anyway so that you can review as much as you'd like to.
The whole codebase is here. It's perma/1 branch of the repository.
Original Content
I have a custom template tag as below:
# other imports
from django.conf import settings
DPS_TEMPLATE_TRUE_DEFAULT = getattr(settings, "DPS_TEMPLATE_TRUE_DEFAULT", "True")
#register.simple_tag(name="var")
def get_var(name, rit=DPS_TEMPLATE_TRUE_DEFAULT, rif="False", rin=""):
"""
A template tag to render value of a variable.
"""
_LOGGER.debug("Rendering value for `%s`...", name)
variable = models.Variable.objects.get(name=name)
value = variable.value
if value is None:
return rin
if isinstance(value, bool):
if value:
return rit
else:
return rif
return variable.value
As you can see, I would like to set rit by DPS_TEMPLATE_TRUE_DEFAULT. I test this behavior as below:
# `template_factory` and `context_factory` creates Template and Context instances accordingly.
# i use them in other tests. they work.
#pytest.mark.it("Render if True by settings")
def test_render_if_true_settings(
self, template_factory, context_factory, variable_factory, settings
):
settings.DPS_TEMPLATE_TRUE_DEFAULT = "this is true by settings"
variable_factory(True)
template = template_factory("FOO", tag_name=self.tag_name).render(
context_factory()
)
assert "<p>this is true by settings</p>" in template
I use pytest-django and, as the docs put, I can kinda mock the settings. However, when I run the test, it does not see DPS_TEMPLATE_TRUE_DEFAULT and uses "True". I debugged this behavior by removing "True" on getattr.
Why does it not see DPS_TEMPLATE_TRUE_DEFAULT even if I set it in tests?
Addition / New Content
In the custom template tag, you can see that I'd like to grab DPS_TEMPLATE_TRUE_DEFAULT from django.conf.settings and use it as rit kwarg in my var tag.
This is where I test this behavior by mutating the related setting with settings fixture of pytest-django and it fails.
As the troubleshooting section states I have also tried the other and possibly official ways to do this, they produce the same behavior. As to why it does that, I have no clue.
Troubleshooting
Using Standard Solutions
The odd thing is I have also tried good-old django.test.utils.override_settings and modify_settings, which show the same behavior.
Eager Initialization
I thought, maybe, the problem was I was using getattr outside the scope of get_var function, which would load it before it executes, which means before the tests and somehow does not let me set it again. So I moved getattr inside get_var function but the behavior was the same. It behaves like DPS_TEMPLATE_TRUE_DEFAULT does not exist in settings.
Hardcoding into Settings File
So I have hardcoded the "failing to see" setting in the settings.py file as below:
DPS_TEMPLATE_TRUE_DEFAULT = "this is true by settings"
Still it behaves like DPS_TEMPLATE_TRUE_DEFAULT does not exist.
This is also proven by removing the default value "True" from getattr in this line.
Environment
Django 2.2.8
Pytest Django 3.7.0
I can't seem to get this to work.
I am trying to send daily a given file, whose name is like 'file_{{ds_nodash}}.csv'.
The problem is that I can't seem to add this name as the filename, since it seems it cant be used. In the text of the email or the subject works perfectly, not not on the name.
Here is the dag as an example:
local_file = 'file-{{ds_nodash}}.csv'
send_stats_csv = EmailOperator(
task_id='send-stats-csv',
to=['email#gmail.com'],
subject='Subject - {{ ds }}',
html_content='Here is the new file.',
files=[local_file],
dag=dag)
Error code:
No such file or directory: u'file-{{ds_nodash}}.csv'
If i write it literally, with its given date, it works flawlessly.
Where am I wrong? How should I go about this?
Any help would be appreciated.
Thanks.
P.D. Copy paste from airflow's documentation - "The Airflow engine passes a few variables by default that are accessible in all templates". https://airflow.incubator.apache.org/code.html
If I understood correctly, these variables are accessible in execution, so if i am executing the dag, the file should be found right? I've tried both testing the task or backfilling the dag with no success.
Airflow Operators define what fields are template fields. For the EmailOperator only the subject and html_content fields are set as templates.
class EmailOperator(BaseOperator):
...
template_fields = ('subject', 'html_content')
template_ext = ('.html',)
See: https://airflow.incubator.apache.org/_modules/email_operator.html
From the Airflow Gotcha's Page (https://gtoonstra.github.io/etl-with-airflow/gotchas.html)
Not all parameters in operators are templated, so you cannot use Jinja templates everywhere. The Jinja templates only work for those fields in operators where it’s listed in the template_fields...
To get this to work, you would have to derive a new class from EmailOperator and add in templating for the files array.
Well, just a try out I see ds_nodash is a template variable. probably you need to give spaces before and after 'ds_nodash', it will be something looks like: 'file-{{ ds_nodash }}.csv'
I have a specific ansible variable structure that I want to get from the vault into a yaml file on my hosts.
Lets assume a structure like this:
secrets:
psp1:
username: this
password: that
secret_key: 123
...
I need something like a "generic" template to output whatever "secrets" contains at the moment, since the content changes almost completely based on the current environment.
The easiest solution I can think of is to output the whole structure in an template like this:
# config/secrets.yml
{{ secrets | to_yaml }}
But the jinja2 to_yaml filter does only "yamlify" the first level, deeper nestings are outputted in json.
Can I work around that problem somehow? Is there an easier way to achieve what I want?
Thanks for any help!
As jwodder said, it's valid.
If you're using to_yaml (instead of to_nice_yaml) you have fairly old install of ansible, it's time to upgrade.
Use to_nice_yaml
It's possible to pass your own kwargs to filter functions, which usually pass them on to underlying python module call. Like this one for your case. So something like:
{{ secrets | to_nice_yaml( width=50, explicit_start=True, explicit_end=True) }}
only catch is you can't override indent=4,* allow_unicode=True, default_flow_style=False
* Note that indent can now be overridden, at least as of Ansible 2.2.0 (I use it to indent 2 spaces to follow coding standards for one project).
Better documentation for to_nice_yaml can be found here.
I've just started learning Python recently and am using Pyramid as my web framework.
I'm trying to add a static view at localhost/images/misc:
config.add_static_view('images', 'C:/Project/Images/')
config.add_static_view('images/misc', 'C:/Path/To/Other/Images/')
But I get an error: File does not exist: C:/Project/images/misc
So it seems that the second line adding images/misc as a static view doesn't have any effect.
I've been searching for a while for a way to do this, but I haven't found anything. Is it possible to add a static view where the name contains a subdirectory? If so, how?
Under the hood, pyramid turns the name part of the add_static_view() method into a Pyramid route predicate of the form name/*subpath (where name can contain slashes itself). A dedicated static asset view is attached to that route predicate.
In your configuration that means there would be both images/*subpath and images/misc/*subpath route predicates, in that order. When you then request a URL with the path images/misc/foo.png Pyramid finds the images/*subpath predicate first, and tries to look up the misc path element in the 'C:/Project/Images/' folder, which fails.
Lucky for you, you can reverse the order of the registrations, simply register the images/misc path first:
config.add_static_view('images/misc', 'C:/Path/To/Other/Images/')
config.add_static_view('images', 'C:/Project/Images/')
Now the images/misc/*subpath predicate is registered first, and will match any images/misc/ URLs before the other predicate is tested.
I want to use the {% url %} tag to get the url of a named view that takes a parameter.
I want to get the URL without the parameter and pass the parameter later using javascript. So I don't know the value of the parameter when the template renders ! If I try the url without parameters then it says "reverse not found"... I know I can hard code the url in my javcascript code but that's not DRY !!!
Thanks !
When I've had to do this in the past, I've used a sentinel value for the parameters, ie one that I know will never be passed for real, and used a regex in Javascript to replace it with the real ones.
{% url my_view "anobviouslyfakeparameter1" "anotherparamthatwillneverhappenforreal" %}
You can try the following:
url(r'^test/(\d+)/$', 'test_view', name='test-view'),
url(r'^test/$', 'test_view', name='test-view'),
And return a 404 if the parameter is not provided (in case someone would actually access this uri).