Is it possible to instantiate a structure (tuple/list) knowing its type (Tuple/List)?

Question:

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:
  1. Extract the type of the return
  2. Extract what’s inside (if, for example, I’m dealing with a tuple/list)
  3. Create an instantiated structure with step 1) and 2). For example: typing.Tuple[int, int] would yield (0, 0) and typing.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.

Asked By: Vincent Pelletier

||

Answers:

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
Categories: questions Tags: , , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.