pass kwargs to re.sub() - python

In Python, I'm trying to implement a pseudo-ternary operator within a template string. A value is inserted into a string if kwargs has a specific key.
re module has a way do exactly what I need in re.sub(), you can pass a function to be called on matches. What I can't do is to pass **kwargs to it. Code follows
import re
template_string = "some text (pseudo_test?val_if_true:val_if_false) some text"
def process_pseudo_ternary(match, **kwargs):
if match.groups()[0] in kwargs:
return match.groups()[1]
else:
return match.groups()[2]
def process_template(ts, **kwargs):
m = re.compile('\((.*)\?(.*):(.*)\)')
return m.sub(process_pseudo_ternary, ts)
print process_template(template_string, **{'pseudo_test':'yes-whatever', 'other_value':42})
line if match.groups()[0] in kwargs: is the problem of course, as process_pseudo_ternary's kwargs are empty.
Any ideas on how to pass these? m.sub(function, string) doesn't take arguments.
The final string is to be: some text val_if_true some text (because the dictionary has the key named 'pseudo_test').
Feel free to redirect me to a different implementation of ternary operator in a string. I'm aware of Python conditional string formatting . I need the ternary to be in the string, not in the string's formatting tuple/dict.

If i understand it correctly, you could use something like http://docs.python.org/library/functools.html#functools.partial
return m.sub(partial(process_pseudo_ternary, custom_1=True, custom_2=True), ts)
EDIT: Changed a little, to match your code better.

Related

Regex Pattern to find arguments passed into a function

For a project, I am trying to read through a python file and keep a list of all the variable being used within a certain function. I am reading through the lines in the python file in string format and then focusing on a line where starting with "def". For the purpose of this example pretend we have the following line identified:
def func(int_var:int,float_var=12.1,string_var=foo()):
I want to use regex or any other method to grab the values within this function declaration.
I want to grab the string "int_var:int,float_var=12.1,string_var=foo()", and later split it based on the commas to get ["int_var:int","float_var=12.1","string_var=foo()"]
I am having a lot of trouble being able to isolate the items between the parenthesis corresponding to 'func'.
Any help creating a regex pattern would be greatly appreciated!
Instead of regex, it is much easier and far more robust to use the ast module:
import ast
s = """
def func(int_var:int,float_var=12.1,string_var=foo()):
pass
"""
def form_sig(sig):
a = sig.args
d = [f'{ast.unparse(a.pop())}={ast.unparse(j)}' for j in sig.defaults[::-1]][::-1]
v_arg = [] if sig.vararg is None else [f'*{sig.vararg.arg}']
kwarg = [] if sig.vararg is None else [f'*{sig.kwark.arg}']
return [*map(ast.unparse, a), *d, *v_arg, *kwarg]
f = [{'name':i.name, 'sig':form_sig(i.args)} for i in ast.walk(ast.parse(s))
if isinstance(i, ast.FunctionDef)]
Output:
[{'name': 'func', 'sig': ['int_var: int', 'float_var=12.1', 'string_var=foo()']}]
func_pattern = re.compile(r'^\s*def\s(?P<name>[A-z_][A-z0-9_]+)\((?P<args>.*)\):$')
match = func_pattern.match('def my_func(arg1, arg2):')
func_name = match.group('name') # my_func
func_args = match.group('args').split(',') # ['arg1', 'arg2']

Is it possible to flip a string in Python "around" a character?

For example let's say I have two strings:
We have the string hello-world and the string world.
I want to create a function called flip(str, arg) that basically takes the string, and "flips" the characters before and after the "arg", if any.
So hello-world passed into flip("hello-world", "-") would become world-hello and flip("world", "-") would still remain world.
An example implementation is as follows, but I am wondering if there is a library function or something for this (I only need in one location, making a function doesn't seem right). I can't seem to find what I am looking for.
def flip(s, arg):
if arg not in s:
return s
index = s.find(arg)
return s[index+1:] + arg + s[:index]
You can use str.partition, then reverse the splits and join:
def flip(s, arg):
return ''.join(s.partition(arg)[::-1])
flip('hello-world', '-')
# 'world-hello'
flip('world', '-')
# 'world'
Note that if the string has multiple occurrences of arg, the string is partitioned on the first one only.
flip("hello-my-world", '-')
# 'my-world-hello'
If you want a complete flip (reversal), you may instead consider str.split and str.join:
def flip2(s, arg):
return arg.join(s.split(arg)[::-1])
flip2("hello-my-world", '-')
# 'world-my-hello'
if you are looking for one liner you can do the following -
"-".join("Hello-world".split('-')[::-1])
so for a more general solution, you can first define arg, and string:
arg = '-'
string = 'hello-world'
and then use -
arg.join(string.split(arg)[::-1])

A more concise way to write this Python code

In Python, I'd like to test for the existence of a keyword in the output of a Linux command. The keywords to test for would be passed as a list as shown below. I've not spent a lot of time with Python so brute-force approach is below. Is there a cleaner way to write this?
def test_result (result, mykeys):
hit = 0
for keyword in mykeys:
if keyword in result:
hit = 1
print "found a match for " + keyword
if hit == 1:
return True
result = "grep says awk"
mykeys = ['sed', 'foo', 'awk']
result = test_result (result, mykeys)
The any built-in will do it.
def test_result(result, mykeys):
return any(key in result for key in mykeys)
You can use a regular expression to accomplish this. A regular expression of the form a|b|c matches any of a, b or c. So, you'd want something of the form:
import re
p = re.compile('|'.join(mykeys))
return bool(p.search(result))
p.search(result) searches the entire string for a match of the regular expression; it returns a match (which is truth-y) if present and returns None (which is false-y) otherwise. Converting the result to bool gives True if it matches and False otherwise.
Putting this together, you'd have:
import re
def test_result(result, mykeys):
p = re.compile('|'.join(mykeys))
return bool(p.search(result))
You can also make this more concise by not pre-compiling the regular expression; this should be fine if it's a one-time use:
def test_result(result, mykeys):
return bool(re.search('|'.join(mykeys), result))
For reference, read about Python's re library.
Your function does two things, printing and returning the result. You could break them up like so:
def test_result(result, mykeys):
return [k in result for k in mykeys]
def print_results(results):
for result in results:
print("found a match for " + result)
test_result will return a list with all the found keys, or an empty list. The empty list is falsey, so you can use it for whatever tests you want. The print_results is only needed if you actually want to print, otherwise you can use the result in some other function.
If you only want to check for the presence and don't care about which key you found, you can do something like:
def test_result(result, my_keys):
return any(map(lambda k: k in result, mykeys))
If you're using python3 (as you should be), I believe this will be lazy and only evaluate as much of the list as necessary.
See A more concise way to write this Python code for a more concise version of this last function.
To search for an element in a list, you can use a for-else statement. In particular, this allows to return the found element.
def test_result (result, mykeys):
for keyword in mykeys:
if keyword in result: break
else:
return None
return keyword
print(test_result("grep says awk", ['sed', 'foo', 'awk'])) # 'awk'
print(test_result("grep says awk", ['bar', 'foo'])) # None

How to ask sympy to don't translate bm to boldsymbol?

I'm in the situation where the enduser can define a variable name by himself.
For instance: a variable called "tbm_al" is correct.
In order to pprint variable as latex, I'm using sympy.latex and expecting to have something like "tbm" with "al" as indice, but bm is translated in boldsymbol.
Is there a way to have both "tbm" with indice "al" and neither t (bold) with indice al nor tbm_al as string ?
like:
\begin{equation*}\begin{equation}{tbm}_{al}\end{equation}\end{equation*}
This autotranslation of bm is performed by the Sympy latex printer (sympy.printing.latex), specifically as bm is an entry in the variable modifiers dictionary modifier_dict declared in sympy.printing.latex. I see no way in the source to disable the use of the modifier dict upon call latex(expr, **settings); from what I can see, not settings are not used anywhere in the same context as the modifier_dict dictionary.
Have a look at e.g. the function translate(s) in the source:
def translate(s):
Check for a modifier ending the string. If present, convert the
modifier to latex and translate the rest recursively.
...
From the source of this function, it's quite clear that the modifier dictionary will be checked (recursively) for all entries in the argument expression.
The remaining option would then be to manually modify the name modifiers (modifier_dict) in your own custom source copy of sympy.printing.latex (or, alternatively, in the original), by simply removing the dictionary entry for key bm. This is, of course, unless you want to make use of bm elsewhere.
See also:
http://docs.sympy.org/dev/modules/printing.html#sympy.printing.latex.latex
Thx to #dfri. I decided to clear modifier_dict during latex translate.
from sympy.printing.latex import modifier_dict
from sympy import latex
def cancel_sympy_translate(f):
def wrapper(*args, **kwargs):
saved_dict = dict(modifier_dict)
modifier_dict.clear()
result = f(*args, **kwargs)
modifier_dict.update(saved_dict)
return result
return wrapper
latex = cancel_sympy_translate(latex)
t = Symbol("tbm_al")
print latex(t, mode="equation")
\begin{equation}tbm_{al}\end{equation}
with the "keep_translate_keys". (suggested by #dfri)
def cancel_sympy_translate(f, keep_translate_keys=None):
keep_translate_keys = keep_translate_keys or []
def remove_unwanted_keys(modif_dict):
for k in modif_dict.keys():
if k in keep_translate_keys:
continue
del modif_dict[k]
def wrapper(*args, **kwargs):
saved_dict = dict(modifier_dict)
remove_unwanted_keys(modifier_dict)
result = f(*args, **kwargs)
modifier_dict.update(saved_dict)
return result
return wrapper
latex = cancel_sympy_translate(latex, keep_translate_keys=["bar"])
t = Symbol("tbm_abar")
print latex(t, mode="equation")
\begin{equation}tbm_{\bar{a}}\end{equation}

python convert a string to an operator

Is it possible to convert a string to an operator in python?
I would like to pass a condition to a function
Ideally it would look like this:
def foo(self, attribute, operator_string, right_value):
left_value = getattr(self, attribute)
if left_value get_operator(operator_string) right_value:
return True
else:
return False
bar.x = 10
bar.foo('x', '>', 10)
[out] False
bar.foo('x', '>=', 10)
[out] True
I could make a dictionary where keys are strings and values are functions of the operator module.
I would have to change foo definition slightly:
operator_dict = {'>', operator.lt,
'>=', operator.le}
def foo(self, attribute, operator_string, right_value):
left_value = getattr(self, attribute)
operator_func = operator_dict[operator_string]
if operator_func(left_value, right_value):
return True
else:
return False
This means I have to make this dictionary, but is it really necessary?
You can use eval to dynamically build a piece of Python code and execute it, but apart from that there are no real alternatives. The dictionary-based solution is much more elegant and safe, however.
Apart from that, is it really that bad? Why not shorten it a bit …
return operator_dict[operator_string](left_value, right_value)
The way the problem is specified I don't see why you can't pass operator.le to the function instead of ">=".
If this operator_string coming from a database or file or something or are you passing it around in your code?
bar.foo('x', operator.le , 10)
Are you just looking to have a convenient shorthand? Then you might do something like:
from operator import le
bar.foo('x', le, 10)
If the real problem here is that you have code or business rules coming in from a database or datafile then maybe you actually need to look at writing a little parser that will map your input into these objects and then you could take a look at using a library like pyparsing, ply, codetalker, etc.
#This is very simple to do with eval()
score=1
trigger_conditon=">="
trigger_value=4
eval(f"{score}{trigger_conditon}{trigger_value}")
#luckily fstring also takes care of int/float or relavaent datatype
operator_str="ge"
import operator
eval(f"operator.{operator_str}({score},{trigger_value})")

Categories