mkinit.static_analysis module

A paired down version of static_anslysis from xdoctest

mkinit.static_analysis._parse_static_node_value(node)[source]

Extract a constant value from a node if possible

mkinit.static_analysis.parse_static_value(key, source=None, fpath=None)[source]

Statically parse a constant variable’s value from python code.

TODO: This does not belong here. Move this to an external static analysis library.

Parameters:
  • key (str) – name of the variable

  • source (str | None) – python text

  • fpath (str | None) – filepath to read if source is not specified

Example

>>> key = 'foo'
>>> source = 'foo = 123'
>>> assert parse_static_value(key, source=source) == 123
>>> source = 'foo = "123"'
>>> assert parse_static_value(key, source=source) == '123'
>>> source = 'foo = [1, 2, 3]'
>>> assert parse_static_value(key, source=source) == [1, 2, 3]
>>> source = 'foo = (1, 2, "3")'
>>> assert parse_static_value(key, source=source) == (1, 2, "3")
>>> source = 'foo = {1: 2, 3: 4}'
>>> assert parse_static_value(key, source=source) == {1: 2, 3: 4}
>>> #parse_static_value('bar', source=source)
>>> #parse_static_value('bar', source='foo=1; bar = [1, foo]')
mkinit.static_analysis.package_modpaths(pkgpath, with_pkg=False, with_mod=True, followlinks=True, recursive=True, with_libs=False, check=True)[source]

Finds sub-packages and sub-modules belonging to a package.

Parameters:
  • pkgpath (str) – path to a module or package

  • with_pkg (bool) – if True includes package __init__ files (default = False)

  • with_mod (bool) – if True includes module files (default = True)

  • exclude (list) – ignores any module that matches any of these patterns

  • recursive (bool) – if False, then only child modules are included

  • with_libs (bool) – if True then compiled shared libs will be returned as well

  • check (bool) – if False, then then pkgpath is considered a module even if it does not contain an __init__ file.

Yields:

str – module names belonging to the package

References

http://stackoverflow.com/questions/1707709/list-modules-in-py-package

Example

>>> from mkinit.static_analysis import *
>>> pkgpath = util_import.modname_to_modpath('mkinit')
>>> paths = list(package_modpaths(pkgpath))
>>> print('\n'.join(paths))
>>> names = list(map(util_import.modpath_to_modname, paths))
>>> assert 'mkinit.static_mkinit' in names
>>> assert 'mkinit.__main__' in names
>>> assert 'mkinit' not in names
>>> print('\n'.join(names))
mkinit.static_analysis.is_balanced_statement(lines)[source]

Checks if the lines have balanced parens, brakets, curlies and strings

Parameters:

lines (list) – list of strings

Returns:

False if the statement is not balanced

Return type:

bool

Doctest

>>> assert is_balanced_statement(['print(foobar)'])
>>> assert is_balanced_statement(['foo = bar']) is True
>>> assert is_balanced_statement(['foo = (']) is False
>>> assert is_balanced_statement(['foo = (', "')(')"]) is True
>>> assert is_balanced_statement(
...     ['foo = (', "'''", ")]'''", ')']) is True
>>> #assert is_balanced_statement(['foo = ']) is False
>>> #assert is_balanced_statement(['== ']) is False
mkinit.static_analysis._locate_ps1_linenos(source_lines)[source]

Determines which lines in the source begin a “logical block” of code.

Note

implementation taken from xdoctest.parser

Parameters:

source_lines (list) – lines belonging only to the doctest src these will be unindented, prefixed, and without any want.

Returns:

a list of indices indicating which lines

are considered “PS1” and a flag indicating if the final line should be considered for a got/want assertion.

Return type:

(list, bool)

Example

>>> source_lines = ['>>> def foo():', '>>>     return 0', '>>> 3']
>>> linenos, eval_final = _locate_ps1_linenos(source_lines)
>>> assert linenos == [0, 2]
>>> assert eval_final is True

Example

>>> source_lines = ['>>> x = [1, 2, ', '>>> 3, 4]', '>>> print(len(x))']
>>> linenos, eval_final = _locate_ps1_linenos(source_lines)
>>> assert linenos == [0, 2]
>>> assert eval_final is True
mkinit.static_analysis._workaround_16806(ps1_linenos, exec_source_lines)[source]

workaround for python issue 16806 (https://bugs.python.org/issue16806)

Issue causes lineno for multiline strings to give the line they end on, not the line they start on. A patch for this issue exists https://github.com/python/cpython/pull/1800

Note

Starting from the end look at consecutive pairs of indices to inspect the statment it corresponds to. (the first statment goes from ps1_linenos[-1] to the end of the line list.

Implementation taken from xdoctest.parser