aerosandbox.tools.inspect_tools =============================== .. py:module:: aerosandbox.tools.inspect_tools Functions --------- .. autoapisummary:: aerosandbox.tools.inspect_tools.get_caller_source_location aerosandbox.tools.inspect_tools.get_source_code_from_location aerosandbox.tools.inspect_tools.get_caller_source_code aerosandbox.tools.inspect_tools.get_function_argument_names_from_source_code aerosandbox.tools.inspect_tools.codegen aerosandbox.tools.inspect_tools.dashes Module Contents --------------- .. py:function:: get_caller_source_location(stacklevel = 1) Gets the file location where this function itself (`get_caller_source_location()`) is called. This is not usually useful by itself. However, with the use of the `stacklevel` argument, you can get the call location at any point arbitrarily high up in the call stack from this function. This potentially lets you determine the file location where any Python object was declared. Examples: Consider the file below (and assume we somehow have this function in scope): my_file.py: >>> def my_func(): >>> print( >>> get_caller_source_location(stacklevel=2) >>> ) >>> >>> if_you_can_see_this_it_works = my_func() This will print out the following: (/path/to/my_file.py, 5, "if_you_can_see_this_it_works = my_func() ") Args: stacklevel: Choose the level of the stack that you want to retrieve source code at. Higher integers will get you higher (i.e., more end-user-facing) in the stack. Same behaviour as the `stacklevel` argument in warnings.warn(). Returns: A tuple of: (filename, lineno, code_context) * `filename`: a Path object (see `pathlib.Path` from the standard Python library) of the file where this function was called. * `lineno`: the line number in the file where this function was called. * `code_context`: the immediate line of code where this function was called. A string. Note that, in the case of multiline statements, this may not be a complete Python expression. Includes the trailing newline character (" ") at the end. .. py:function:: get_source_code_from_location(filename, lineno, code_context = None, strip_lines = False) Gets the source code of the single statement that begins at the file location specified. File location must, at a minimum, contain the filename and the line number. Optionally, you can also provide `code_context`. These should have the format: * `filename`: a Path object (see `pathlib.Path` from the standard Python library) of the file where this function was called. * `lineno`: the line number in the file where this function was called. Optionally, you can also provide `code_context`, which has the format: * `code_context`: the immediate line of code where this function was called. A string. Note that, in the case of multiline statements, this may not be a complete Python expression. You can get source code from further up the call stack by using the `stacklevel` argument. Args: filename: a Path object (see `pathlib.Path` from the standard Python library) of the file where this function was called. Alternatively, a string containing a filename. lineno: the line number in the file where this function was called. An integer. Should refer to the first line of a string in question. code_context: Optional. Should be a string containing the immediate line of code at this location. If provided, allows short-circuiting (bypassing file I/O) if the line is a complete expression. strip_lines: A boolean flag about whether or not to strip leading and trailing whitespace off each line of a multi-line function call. See the built-in string method `str.strip()` for behaviour. Returns: The source code of the call, as a string. Might be a multi-line string (i.e., contains ' ' characters) if the call is multi-line. Almost certainly (but not guaranteed due to edge cases) to be a complete Python expression. .. py:function:: get_caller_source_code(stacklevel = 1, strip_lines = False) Gets the source code of wherever this function is called. You can get source code from further up the call stack by using the `stacklevel` argument. Args: stacklevel: Choose the level of the stack that you want to retrieve source code at. Higher integers will get you higher (i.e., more end-user-facing) in the stack. Same behaviour as the `stacklevel` argument in warnings.warn(). strip_lines: A boolean flag about whether or not to strip leading and trailing whitespace off each line of a multi-line function call. See the built-in string method `str.strip()` for behaviour. Returns: The source code of the call, as a string. Might be a multi-line string (i.e., contains ' ' characters) if the call is multi-line. Almost certainly (but not guaranteed due to edge cases) to be a complete Python expression. .. py:function:: get_function_argument_names_from_source_code(source_code) Gets the names of the function arguments found in a particular line of source code. Specifically, it retrieves the names of the arguments in the first function call found in the source code string. If the source code line is an assignment statement, only the right-hand-side of the line is analyzed. Also, removes all line breaks (' '). Examples function inputs and outputs: "f(a, b)" -> ['a', 'b'] "f(a,b)" -> ['a', 'b'] "f( a, b)" -> ['a', 'b'] "g = f(a, b)" -> ['a', 'b'] "g.h = f(a, b)" -> ['a', 'b'] "g.h() = f(a, b)" -> ['a', 'b'] "g.h(i=j) = f(a, b)" -> ['a', 'b'] "f(a, b) + g(h)" -> ['a', 'b'] "f(a: int, b: MyType())" -> ['a', 'b'] "f(a, b).g(c, d)" -> ['a', 'b'] "f(a(b), c)" -> ['a(b)', 'c'] "f(a(b,c), d)" -> ['a(b,c)', 'd'] "f({a:b}, c)" -> ['{a:b}', 'c'] "f(a[b], c)" -> ['a[b]', 'c'] "f({a:b, c:d}, e)" -> ['{a:b, c:d}', 'e'] "f({a:b, c:d}, e)" -> ['{a:b,c:d}', 'e'] "f(dict(a=b,c=d), e)" -> ['dict(a=b,c=d)', 'e'] "f(a=1, b=2)" -> ['a=1', 'b=2'] "f()" -> [''] "f(a, [i for i in l])" -> ['a', '[i for i in l]'], "f(incomplete, " -> raises ValueError "3 + 5" -> raises ValueError "" -> raises ValueError Args: source_code: A line of Python source code that includes a function call. Can be a multi-line piece of source code (e.g., includes ' '). Returns: A list of strings containing all the function arguments. If keyword arguments are found, includes both the key and the value, as-written. .. py:function:: codegen(x, indent_str = ' ', _required_imports = None, _recursion_depth = 0) Attempts to generate a string of Python code that, when evaluated, would produce the same value as the input. Also generates the required imports for the code to run. In other words, in general, the following should evaluate True: >>> code, imports = codegen(x) >>> for import_str in imports: >>> exec(import_str) >>> eval(code) == x # Should evaluate True Not guaranteed to work for all inputs, but should work for most common cases. :param x: The object to generate the code of. :param indent_str: The string to use for indentation. Defaults to four spaces. :param _required_imports: A set of strings containing the names of all required imports. This is an internal :param argument that should not be used by the user.: :param _recursion_depth: The current recursion depth. This is an internal argument that should not be used by the user. Returns: A tuple containing: - The string of Python code that, when evaluated, would produce the same value as the input. - A set of strings that, when evaluated, would import all the required imports for the code to run. .. rubric:: Examples >>> codegen(5) ('5', set()) >>> codegen([1, 2, 3]) ('[1, 2, 3]', set()) >>> codegen(np.array([1, 2, 3])) ('np.array([1, 2, 3])', {'import numpy as np'}) >>> codegen(dict(my_int=4, my_array=np.array([1, 2, 3]))) ('{ 'my_int': 4, 'my_array': np.array([1, 2, 3]), }', {'import numpy as np'}) .. py:function:: dashes() A quick macro for drawing some dashes, to make the terminal output clearer to distinguish.