Source code for pydeps.configs

    
from io import StringIO
import json
import warnings
import logging

log = logging.getLogger(__name__)

# from devtools import debug


HAVE_TOML = False
try:
    import tomllib as toml
    HAVE_TOML = True
except ImportError:
    try:
        import tomlkit as toml
        HAVE_TOML = True
    except ImportError:
        try:
            import toml
            HAVE_TOML = True
        except ImportError:
            pass


[docs] def is_string(v): return isinstance(v, str)
[docs] def boolval(v): if isinstance(v, bool): return v if isinstance(v, int): return bool(v) if is_string(v): v = v.lower() if v in {'j', 'y', 'ja', 'yes', '1', 'true'}: return True if v in {'n', 'nei', 'no', '0', 'false'}: return False raise ValueError("Don't know how to convert %r to bool" % v)
[docs] def listval(v): if is_string(v): return [x for x in v.split() if x.strip()] if isinstance(v, (list, tuple)): return v raise ValueError("Don't know how to convert %r to list" % v)
[docs] def identity(v): return v
typefns = { 'BOOL': boolval, 'INT': int, 'LIST': listval, 'STR': str, }
[docs] def load_toml(filename): if not HAVE_TOML: return {} try: with open(filename) as fp: res = toml.loads(fp.read()) return res['tool']['pydeps'] except Exception as e: log.debug("Couldn't load toml file %s: %s", filename, e) return {}
[docs] def load_json(filename): try: with open(filename) as fp: res = json.loads(fp.read()) return res['pydeps'] except (json.JSONDecodeError, KeyError): return {}
[docs] def load_yaml(filename): try: import yaml from yaml import Loader with open(filename) as fp: res = yaml.load(fp.read(), Loader=Loader) return res['pydeps'] except (yaml.YAMLError, KeyError, ImportError): return {}
[docs] def load_ini(filename): import configparser conf = configparser.ConfigParser() conf.read(filename) try: config = conf.items("pydeps") return dict(config) except (configparser.NoOptionError, configparser.NoSectionError): warnings.warn(' '.join(""" Couldn't find a [pydeps] section in your config files %r -- or it was empty """.split()) % filename) return {}
[docs] def load_config(filename): if filename.endswith('.toml'): return load_toml(filename) if filename.endswith('.json'): return load_json(filename) if filename.endswith('.yaml'): return load_yaml(filename) raise ValueError("Unknown config file type: %s" % filename)
# this class is generated from pydeps.arguments.Arguments.write_default_config()
[docs] class Config(object): #: turn on all the show and verbose options (mainly for debugging pydeps #: itself) debug = False #: specify config file config = None #: disable processing of config files no_config = False #: print pydeps version version = False #: set log-level to one of CRITICAL, ERROR, WARNING, INFO, DEBUG, NOTSET. log = None #: tries to automatically find the name of the current package. find_package = False #: filename fname = None #: be more verbose (-vv, -vvv for more verbosity) verbose = 0 #: write output to 'file' output = None #: output format (svg|png) format = 'svg' #: program to use to display the graph (png or svg file depending on the T #: parameter) display = None #: don't call external program to display graph no_show = False #: show output of dependency analysis show_deps = False #: show output of dependency analysis before removing skips show_raw_deps = False #: write output of dependency analysis to 'file' deps_out = None #: show output of dot conversion show_dot = False #: write dot code to 'file' dot_out = None #: skip dot conversion no_dot = False #: don't create .svg/.png file, implies --no-show (-t/-o will be ignored) no_output = False #: show only import cycles show_cycles = False #: set the ModuleFinder.debug flag to this value debug_mf = 0 #: exclude sources or sinks with degree greater than noise-level noise_level = 200 #: exclude nodes that are more than n hops away (default=2, 0 -> infinite) max_bacon = 2 #: coalesce deep modules to at most n levels max_module_depth = 0 #: include python std lib modules pylib = False #: include python all std lib modules (incl. C modules) pylib_all = False #: include modules that are not installed (or can't be found on sys.path) include_missing = False #: input files to skip (e.g. `foo.*`), multiple file names can be provided exclude = [] #: same as --exclude, except requires the full match. `-xx foo.bar` will #: exclude foo.bar, but not foo.bar.blob exclude_exact = [] #: only include modules that start with MODULE_PATH only = [] #: create list of direct external dependencies externals = False #: draw arrows to (instead of from) imported modules reverse = False #: set the direction of the graph, legal values are TB (default, imported #: modules above importing modules), BT (opposite direction of TB), #: LR (left-to-right), and RL (right-to-left) rankdir = 'TB' #: draw external dependencies as separate clusters cluster = False #: the minimum number of nodes a dependency must have before being clustered #: (default=0) min_cluster_size = 0 #: the maximum number of nodes a dependency can have before the cluster is #: collapsed to a single node (default=0) max_cluster_size = 0 #: draw target module as a cluster keep_target_cluster = False #: collapse target module (--keep-target-cluster will be ignored) collapse_target_cluster = False #: remove PREFIX from the displayed name of the nodes rmprefix = [] #: starting value for hue from 0 (red/default) to 360. start_color = 0 def __init__(self, **kwargs): for key in dir(self.__class__): if not key.startswith('_'): val = getattr(self.__class__, key) if not callable(val): setattr(self, key, val) self.__dict__.update(kwargs) def __eq__(self, other): res = True for (lkey, lval), (rkey, fval) in zip(iter(self), iter(other)): if lkey != rkey: print(f"key mismatch: {lkey} != {rkey}") res = False if lval != fval: print(f"val mismatch {lkey}: {lval} != {fval}") res = False return res
[docs] def set_field(self, field, value): if field == 'fname': self.fname = identity(value) if field == 'verbose': self.verbose = int(value) if field == 'output': self.output = identity(value) if field == 'format': self.format = str(value) if field == 'display': self.display = identity(value) if field == 'no_show': self.no_show = boolval(value) if field == 'show_deps': self.show_deps = boolval(value) if field == 'show_raw_deps': self.show_raw_deps = boolval(value) if field == 'deps_out': self.deps_out = identity(value) if field == 'show_dot': self.show_dot = boolval(value) if field == 'dot_out': self.dot_out = identity(value) if field == 'no_dot': self.no_dot = boolval(value) if field == 'no_output': self.no_output = boolval(value) if field == 'show_cycles': self.show_cycles = boolval(value) if field == 'debug_mf': self.debug_mf = int(value) if field == 'noise_level': self.noise_level = int(value) if field == 'max_bacon': self.max_bacon = int(value) if field == 'max_module_depth': self.max_module_depth = int(value) if field == 'pylib': self.pylib = boolval(value) if field == 'pylib_all': self.pylib_all = boolval(value) if field == 'include_missing': self.include_missing = boolval(value) if field == 'exclude': self.exclude = listval(value) if field == 'exclude_exact': self.exclude_exact = listval(value) if field == 'only': self.only = listval(value) if field == 'externals': self.externals = boolval(value) if field == 'reverse': self.reverse = boolval(value) if field == 'rankdir': self.rankdir = str(value) if field == 'cluster': self.cluster = boolval(value) if field == 'min_cluster_size': self.min_cluster_size = int(value) if field == 'max_cluster_size': self.max_cluster_size = int(value) if field == 'keep_target_cluster': self.keep_target_cluster = boolval(value) if field == 'collapse_target_cluster': self.collapse_target_cluster = boolval(value) if field == 'rmprefix': self.rmprefix = listval(value) if field == 'start_color': self.start_color = int(value)
def __iter__(self): return iter(self.__dict__.items()) def __getattr__(self, name): return self.__dict__[name]
[docs] def update(self, data): if set(data.keys()) - set(self.__dict__.keys()): warnings.warn("Unknown config keys: %s" % (set(data.keys()) - set(self.__dict__.keys()))) for k, v in data.items(): if k in self.__dict__: self.set_field(k, v)
[docs] def write_ini(self): import configparser cfg = configparser.ConfigParser() cfg['pydeps'] = {k: str(v) for k, v in self} with StringIO() as fp: cfg.write(fp) return fp.getvalue()
[docs] def write_toml(self): import tomlkit return tomlkit.dumps({ 'tools.pydeps': {k: v for k, v in self if v is not None} })
[docs] def write_json(self): data = {'pydeps': self.__dict__} return json.dumps(data, indent=4)
[docs] def write_yaml(self): import yaml data = {'pydeps': self.__dict__} return yaml.dump(data, default_flow_style=False)
[docs] @classmethod def load(cls, fnames): """Load config from file. """ conf = cls() for fname in fnames: ftype = filetype(fname) if ftype == 'toml': conf.update(load_toml(fname)) if ftype == 'json': conf.update(load_json(fname)) if ftype == 'yaml': conf.update(load_yaml(fname)) if ftype == 'ini': conf.update(load_ini(fname)) return conf
[docs] def filetype(fname): if fname.endswith('.toml'): return 'toml' elif fname.endswith('.json'): return 'json' elif fname.endswith('.yaml'): return 'yaml' elif fname.endswith('.yml'): return 'yaml' elif fname.endswith('.ini'): return 'ini' else: return 'ini'