I have a template that uses placeholders for the varying content that will be filled in. Suppose the template has:
"This article was written by AUTHOR, who is solely responsible for its content."
The author's name is stored in the variable author.
So I of course do:
wholeThing = wholeThing.replace('AUTHOR', author)
The problem is I have 10 of these self-named variables, and it would just be more economical if I could something like this, using only 4 for brevity:
def(self-replace):
...
return
wholeThing = wholeThing.self-replace('AUTHOR', 'ADDR', 'PUBDATE', 'MF_LINK')
With Python 3.6+, you may find formatted string literals (PEP 498) efficient:
# data from #bohrax
d = {"publication": "article", "author": "Me"}
template = f"This {d['publication']} was written by {d['author']}, who is solely responsible for its content."
print(template)
This article was written by Me, who is solely responsible for its content.
Sounds like what you need is string formatting, something like this:
def get_sentence(author,pud_date):
return "This article was written by {}, who is solely responsible for its content. This article was published on {}.".format(author,pub_date)
Assuming you are parsing the variables that make up the string iteratively, you can call this function with the arguments needed and get the string returned.
That str.format() function can be placed anywhere and can take any number of arguments as long as there is a place for it in the string indicated by the {}. I suggest you play around with this function on the interpreter or ipython notebook to get familiar with it.
If you have control over the templates I would use str.format and a dict containing the variables:
>>> template = "This {publication} was written by {author}, who is solely responsible for its content."
>>> variables = {"publication": "article", "author": "Me"}
template.format(**variables)
'This article was written by Me, who is solely responsible for its content.'
It is easy to extend this to a list of strings:
templates = [
"String with {var1}",
"String with {var2}",
]
variables = {
"var1": "value for var1",
"var2": "value for var2",
}
replaced = [template.format(**variables) for template in templates]
Related
i recently started using the marqo library and i am trying to add document so that marqo can search and return the relevant part of the document but i keep getting error when i run the the code.
i used the
add_document()
method and i pass the document as a string for search but it returns an error. Here is what my code look like;
import marqo
DOCUMENT = 'the document'
mq = marqo.Client(url='http://localhost:8882')
mq.index("my-first-index").add_documents(DOCUMENT)
and when i run it i get a
MarqoWebError
you are getting the error because the add_document() method takes a list of python dictionaries as an argument not a string, so you are to pass the document as a value to any key you assign to it. But it is advisable to add a title and also an id for later referencing. Here is what i mean;
mq.index("my-first-index").add_documents([
{
"Title": the_title_of_your_document,
"Description": your_document,
"_id": your_id,
}]
)
the id can be any string of your choice. You can add as many dictionaries as you want to the list, each dictionary represents a document.
I think the documents need to be a list of dicts. See here https://marqo.pages.dev/API-Reference/documents/
I want to use f-string with my string variable, not with string defined with a string literal, "...".
Here is my code:
name=["deep","mahesh","nirbhay"]
user_input = r"certi_{element}" # this string I ask from user
for element in name:
print(f"{user_input}")
This code gives output:
certi_{element}
certi_{element}
certi_{element}
But I want:
certi_{deep}
certi_{mahesh}
certi_{nirbhay}
How can I do this?
f"..." strings are great when interpolating expression results into a literal, but you don't have a literal, you have a template string in a separate variable.
You can use str.format() to apply values to that template:
name=["deep","mahesh","nirbhay"]
user_input = "certi_{element}" # this string i ask from user
for value in name:
print(user_input.format(element=value))
String formatting placeholders that use names (such as {element}) are not variables. You assign a value for each name in the keyword arguments of the str.format() call instead. In the above example, element=value passes in the value of the value variable to fill in the placeholder with the element.
Unlike f-strings, the {...} placeholders are not expressions and you can't use arbitrary Python expressions in the template. This is a good thing, you wouldn't want end-users to be able to execute arbitrary Python code in your program. See the Format String Syntax documenation for details.
You can pass in any number of names; the string template doesn't have to use any of them. If you combine str.format() with the **mapping call convention, you can use any dictionary as the source of values:
template_values = {
'name': 'Ford Prefect',
'number': 42,
'company': 'Sirius Cybernetics Corporation',
'element': 'Improbability Drive',
}
print(user_input.format(**template_values)
The above would let a user use any of the names in template_values in their template, any number of times they like.
While you can use locals() and globals() to produce dictionaries mapping variable names to values, I'd not recommend that approach. Use a dedicated namespace like the above to limit what names are available, and document those names for your end-users.
If you define:
def fstr(template):
return eval(f"f'{template}'")
Then you can do:
name=["deep","mahesh","nirbhay"]
user_input = r"certi_{element}" # this string i ask from user
for element in name:
print(fstr(user_input))
Which gives as output:
certi_deep
certi_mahesh
certi_nirbhay
But be aware that users can use expressions in the template, like e.g.:
import os # assume you have used os somewhere
user_input = r"certi_{os.environ}"
for element in name:
print(fstr(user_input))
You definitely don't want this!
Therefore, a much safer option is to define:
def fstr(template, **kwargs):
return eval(f"f'{template}'", kwargs)
Arbitrary code is no longer possible, but users can still use string expressions like:
user_input = r"certi_{element.upper()*2}"
for element in name:
print(fstr(user_input, element=element))
Gives as output:
certi_DEEPDEEP
certi_MAHESHMAHESH
certi_NIRBHAYNIRBHAY
Which may be desired in some cases.
If you want the user to have access to your namespace, you can do that, but the consequences are entirely on you. Instead of using f-strings, you can use the format method to interpolate dynamically, with a very similar syntax.
If you want the user to have access to only a small number of specific variables, you can do something like
name=["deep", "mahesh", "nirbhay"]
user_input = "certi_{element}" # this string i ask from user
for element in name:
my_str = user_input.format(element=element)
print(f"{my_str}")
You can of course rename the key that the user inputs vs the variable name that you use:
my_str = user_input.format(element=some_other_variable)
And you can just go and let the user have access to your whole namespace (or at least most of it). Please don't do this, but be aware that you can:
my_str = user_input.format(**locals(), **globals())
The reason that I went with print(f'{my_str}') instead of print(my_str) is to avoid the situation where literal braces get treated as further, erroneous expansions. For example, user_input = 'certi_{{{element}}}'
I was looking for something similar with your problem.
I came across this other question's answer: https://stackoverflow.com/a/54780825/7381826
Using that idea, I tweaked your code:
user_input = r"certi_"
for element in name:
print(f"{user_input}{element}")
And I got this result:
certi_deep
certi_mahesh
certi_nirbhay
If you would rather stick to the layout in the question, then this final edit did the trick:
for element in name:
print(f"{user_input}" "{" f"{element}" "}")
Reading the security concerns of all other questions, I don't think this alternative has serious security risks because it does not define a new function with eval().
I am no security expert so please do correct me if I am wrong.
This is what you’re looking for. Just change the last line of your original code:
name=["deep","mahesh","nirbhay"]
user_input = "certi_{element}" # this string I ask from user
for element in name:
print(eval("f'" + f"{user_input}" + "'"))
I've been looking over some github repos of python scrapy spiders. In this repo I found the following lines of code:
FIRSTPAGE_URL_SYNTAX = 'http://%s.tumblr.com'
OTHERPAGE_URL_SYNTAX = 'http://%s.tumblr.com/page/%s'
name = "tumblr"
According to the documentation and SO thread that I've found, %s requires an in-line reference to a variable. As you can see the code above contains no such reference. Is this working code? Why?
Those variables serve as a template. Later in the code, you'll see something like
FIRSTPAGE_URL_SYNTAX % user
or
OTHERPAGE_URL_SYNTAX % (user, page)
You can do the same thing with {} in strings:
template = "{} blah blah {}"
print(template.format(s1, s2))
This allows for a user to easily repeatedly use this one variable, if they need to reference multiple URLs with similar bodies, as opposed to having to retype the entire URL every time.
Those are just strings. All characters, including %s, are valid in strings. The requirement for a substitution value comes when you use the % operator, which they're not doing here. They're declaring those strings as templates, and will substitute values into them later.
By declaring them all in one place like that, it makes it easier to find them and change them. It's good coding practice.
I am using elasticsearch-dsl-py and would like to filter on a term that is contained inside another one like this:
"slug": {
"foo": "foo-slug",
"bar": "bar-slug "
}
What I do is this :
search.query(‘filtered’, filter={"term": {"slug.foo": "foo-slug"}})
I would prefer something like
search.filter(term, slug.foo="foo-slug")
But I can’t as keyword can’t include dots.
If it helps anyone else, I had the same problem creating this kind of query against a child property not using nested objects. I found the solution was to use the query method instead of the filter method:
search.query('match', **{"slug.foo": "foo-slug"})
This worked for me in ElasticSearch 1.5.2.
edit... DON'T DO THIS: See aaronfay's answer for the correct approach.
This doesn't seem to be documented anywhere which is sad...
>>> search.filter('term', slug__foo='foo-slug').to_dict()
{'query': {'filtered': {'filter': {'term': {u'slug.foo': 'foo-slug'}}, 'query': {'match_all': {}}}}}
The double underscore will be converted into dot notation. No idea if this is stable.
So I am assuming that slug is a nested object in a larger document. In the current version (0.0.8) this can be achieved like so:
from elasticsearch_dsl import F
...
f = F('term', foo='foo-slug')
search = search.filter('nested', path='slug', filter=f)
It's a long time after the question had been asked, but just in case anyone comes across this post, Charles's answer is actually correct, (The method shouldn't break since it's actually mentioned in the packages docs now).
As the docs mention:
...,the Q shortcut (as well as the query, filter, and exclude methods on Search class) allows you to use __ (double underscore) in place of a dot in a keyword argument:
s = Search()
s = s.filter('term', category__keyword='Python')
s = s.query('match', address__city='prague')
It also mentions aaronfay's answer:
Alternatively you can always fall back to python’s kwarg unpacking if
you prefer:
s = Search()
s = s.filter('term', **{'category.keyword': 'Python'})
s = s.query('match', **{'address.city': 'prague'})
This will do the trick for you:
args = {
"slug.foo": "foo-slug"
}
search.filter(term, **args)
Possibly i am overlooking an obvious solution or thinking the wrong way...
I have a limited amount of text, words in a database, that I want to display translated to users in a flask/jinja/babel webapp. eg. "running" is a possible value of an "activity" column and that should be "laufen" for my german users.
Words in templates and code are extracted and put into the catalog, but how do i get additional words into the catalog? Is there a simple text file extractor?
The only thing i could think of is, just create a .py file and put lots of _('...') lines in them, but that feels just wrong... is it?
I created a messages.txt with my "words" like gettext function calls:
_('cycling')
_('running')
and added it to my babel.cfg as python source:
[python: messages.txt]
plain, simple, stupid, but works.
First, start with http://flask.pocoo.org/snippets/4/.
Secondly, you need to store these 'limited' values as integers or enums in database and then create the lookup table for all these enums in code (so Babel knows about them):
i18n_val = {0: _('running'), ...}
# Or multi-level dict with different categories:
i18n_all = {
'activity': {
0: _('running'), ...
'foo': {
0: _('bar..'), ...
}
}
And accessing the translated string from template is now as simple as:
{{ i18n_val[obj.activity] }}
{{ i18n_all['activity'][obj.activity] }}
In order to make the i18n_val and i18n_all variables available for all the templates, just register them with context processors.