Viewing Generated Code
If you wish to see the source code generated by a constructed class you need to access the
MethodMaker instances on that class.
There are helper functions that will do this for you and also retrieve the source code the
MethodMaker objects would generate.
print_generated_code will print the source code for all methods along with any necessary globals
and annotations associated with the method being generated.
get_generated_code will retrieve the GeneratedCode objects that will be used to create the
class methods. These have source_code, globs and annotations attributes.
You can also directly access the MethodMakers with the get_methods function
from pathlib import Path
from pprint import pp
from ducktools.classbuilder import get_generated_code, print_generated_code
from ducktools.classbuilder.prefab import attribute, Prefab
class Example(Prefab):
a: int
b: int = 42
c: list = attribute(default_factory=list)
p: Path = Path("/usr/bin/python")
generated_code = get_generated_code(Example)
pp(generated_code)
Output:
{'__init__': GeneratorOutput(source_code='def __init__(self, a, b=42, c=None, p=_p_default): ...', globs={'_c_factory': <class 'list'>, '_p_default': PosixPath('/usr/bin/python')}, annotations={'a': <class 'int'>, 'b': <class 'int'>, 'c': <class 'list'>, 'p': <class 'pathlib.Path'>, 'return': None}),
'__eq__': GeneratorOutput(source_code='def __eq__(self, other): ...', globs={}, annotations=None),
'__repr__': GeneratorOutput(source_code='def __repr__(self): ...', globs={}, annotations=None),
'__replace__': GeneratorOutput(source_code='def __replace__(self, /, **changes): ...', globs={}, annotations=None)}
print_generated_code(Example) cleans up the output to be more presentable and readable
Source:
def __eq__(self, other):
return (
self.a == other.a
and self.b == other.b
and self.c == other.c
and self.p == other.p
) if self.__class__ is other.__class__ else NotImplemented
def __init__(self, a, b=42, c=None, p=_p_default):
self.a = a
self.b = b
self.c = c if c is not None else _c_factory()
self.p = p
def __replace__(self, /, **changes):
new_kwargs = {'a': self.a, 'b': self.b, 'c': self.c, 'p': self.p}
new_kwargs |= changes
return self.__class__(**new_kwargs)
def __repr__(self):
return f'{type(self).__qualname__}(a={self.a!r}, b={self.b!r}, c={self.c!r}, p={self.p!r})'
Globals:
__init__: {'_c_factory': <class 'list'>, '_p_default': PosixPath('/usr/bin/python')}
Annotations:
__init__: {'a': <class 'int'>, 'b': <class 'int'>, 'c': <class 'list'>, 'p': <class 'pathlib.Path'>, 'return': None}