Issue
I'm currently developing python code to mock a certain C library. I have access to the library functions and docstrings thanks to pybind. The task is to mock the return of these functions.
The situation
So far, I can successfully read any function output using regex. Now, I need to evaluate the type of this output, get what's inside of this type and either instantiate it to a known value or fill it with an object. Here's an example of what I'm trying to explain:
docstring = parse(getattr(MyClass, the_method_I_want_to_mock).__doc__)
# The regex will read from -> to the end of the output hinting
method_type_search = re.search(r"(?<=-> ).+(?=)", docstring.short_description)
# If the regex finds something, evaluate the output
evaluated_method = eval(method_type_search.group(0))
At this point, an evaluated_method
value would evaluate to something like : typing.Tuple[int, int]
The problem
Here's what I'm seeking to do:
- Extract the type of the return
- Extract what's inside (if, for example, I'm dealing with a tuple/list)
- Create an instantiated structure with step 1) and 2). For example:
typing.Tuple[int, int]
would yield(0, 0)
andtyping.List[float, user_class]
would yield[0.0, user_class()]
Here's what I have done so far:
# eval_method is in the form of `typing.Tuple[int, int]` like aforementioned
def test_evaluate_types(eval_method):
#This is the dictionary I plan on using to turn a type (ex: int) into its value (ex: 0).
#If any output requires an instantiated object (ex: typing.Tuple[user_class, int],
#I'll need to instantiate the user_class and turn the int into 0.
evaluate_dict: dict = {
int: 0,
List[int]: [0, 1, 2]
}
out = []
# checks if there is a structure or if its only one type (tuple[int, int] vs int)
try:
eval_method_type = eval_method._name
except AttributeError:
# if it's a simple type, return its value
return evaluate_dict[eval_method]
# This fetches what's inside a structure (ex: [<class 'int'>, <class 'int'>])
eval_method_output = eval_method.__args__
# parsing what is inside the structure and instanciating it.
for idx, output in enumerate(eval_method_output):
out.append(evaluate_dict[output])
#This WOULD casts the list into whatever structure was found earlier.
#It doesn't work and I'm stuck here.
return eval(eval_method_type + f"({out})")
I feel like I'm maybe complicating my issue, but can't seem to find a function/way to easily convert ANY type (even user type) into a chosen output like stated above.
Solution
It seems that the __origin__
dunder can be used to get the necessary tuple
. So then, when I have the string Tuple[int, int]
, I then call an eval()
on it, which gives me typing.Tuple[int, int]
. Using the dunder __origin__
on the eval's result, I then get the tuple
I was looking for and instantiate it directly.
string_to_eval: str = "Tuple[int, int]"
string_eval = eval(string_to_eval) # Yields the aforementionned typing.Tuple[int, int]
tuple_result = string_eval.__origin__() # Yields 'tuple'
Answered By - Vincent Pelletier
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.