Skip to content

dependenpy ¤

Dependenpy package.

Show the inter-dependencies between modules of Python packages.

With dependenpy you will be able to analyze the internal dependencies in your Python code, i.e. which module needs which other module. You will then be able to build a dependency matrix and use it for other purposes.

If you read this message, you probably want to learn about the library and not the command-line tool: please refer to the README.md included in this package to get the link to the official documentation.

Modules:

  • cli –

    Deprecated. Import from dependenpy directly.

  • debug –

    Deprecated. Import from dependenpy directly.

  • dsm –

    Deprecated. Import from dependenpy directly.

  • finder –

    Deprecated. Import from dependenpy directly.

  • helpers –

    Deprecated. Import from dependenpy directly.

  • node –

    Deprecated. Import from dependenpy directly.

  • plugins –

    Deprecated. Import from dependenpy directly.

  • structures –

    Deprecated. Import from dependenpy directly.

Classes:

Functions:

  • get_parser –

    Return the CLI argument parser.

  • guess_depth –

    Guess the optimal depth to use for the given list of arguments.

  • main –

    Run the main program.

Attributes:

  • CSV –

    CSV format.

  • FORMAT –

    Supported output formats.

  • JSON –

    JSON format.

  • TEXT –

    Plain text format.

CSV module-attribute ¤

CSV = 'csv'

CSV format.

FORMAT module-attribute ¤

FORMAT = (CSV, JSON, TEXT)

Supported output formats.

JSON module-attribute ¤

JSON = 'json'

JSON format.

DSM ¤

DSM(
    *packages: str,
    build_tree: bool = True,
    build_dependencies: bool = True,
    enforce_init: bool = True,
)

Bases: RootNode, NodeMixin, PrintMixin

DSM-capable class.

Technically speaking, a DSM instance is not a real DSM but more a tree representing the Python packages structure. However, it has the necessary methods to build a real DSM in the form of a square matrix, a dictionary or a tree-map.

Parameters:

  • *packages ¤

    (str, default: () ) –

    List of packages to search for.

  • build_tree ¤

    (bool, default: True ) –

    Auto-build the tree or not.

  • build_dependencies ¤

    (bool, default: True ) –

    Auto-build the dependencies or not.

  • enforce_init ¤

    (bool, default: True ) –

    If True, only treat directories if they contain an __init__.py file.

Methods:

  • __bool__ –

    Node as Boolean.

  • __contains__ –

    Get result of _contains, cache it and return it.

  • __getitem__ –

    Return the corresponding Package or Module object.

  • as_dict –

    Return the dependencies as a dictionary.

  • as_graph –

    Create a graph with self as node, cache it, return it.

  • as_matrix –

    Create a matrix with self as node, cache it, return it.

  • as_treemap –

    Return the dependencies as a TreeMap.

  • build_dependencies –

    Recursively build the dependencies for sub-modules and sub-packages.

  • build_tree –

    Build the Python packages tree.

  • get –

    Get item through __getitem__ and cache the result.

  • get_target –

    Get the result of _get_target, cache it and return it.

  • print –

    Print the object in a file or on standard output by default.

  • print_graph –

    Print the graph for self's nodes.

  • print_matrix –

    Print the matrix for self's nodes.

  • print_treemap –

    Print the matrix for self's nodes.

Attributes:

Source code in src/dependenpy/_internal/dsm.py
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
def __init__(
    self,
    *packages: str,
    build_tree: bool = True,
    build_dependencies: bool = True,
    enforce_init: bool = True,
):
    """Initialization method.

    Parameters:
        *packages: List of packages to search for.
        build_tree: Auto-build the tree or not.
        build_dependencies: Auto-build the dependencies or not.
        enforce_init: If True, only treat directories if they contain an `__init__.py` file.
    """
    self.base_packages: tuple[str, ...] = packages
    """Packages initially specified."""
    self.finder: Finder = Finder()
    """Finder instance for locating packages and modules."""
    self.specs: list[PackageSpec] = []
    """List of package specifications found."""
    self.not_found: list[str] = []
    """List of packages that were not found."""
    self.enforce_init: bool = enforce_init
    """Whether to enforce the presence of `__init__.py` files."""

    specs = []
    for package in packages:
        spec = self.finder.find(package, enforce_init=enforce_init)
        if spec:
            specs.append(spec)
        else:
            self.not_found.append(package)

    if not specs:
        print("** dependenpy: DSM empty.", file=sys.stderr)  # noqa: T201

    self.specs = PackageSpec.combine(specs)

    for module in self.not_found:
        print(f"** dependenpy: Not found: {module}.", file=sys.stderr)  # noqa: T201

    super().__init__(build_tree)

    if build_tree and build_dependencies:
        self.build_dependencies()

base_packages instance-attribute ¤

base_packages: tuple[str, ...] = packages

Packages initially specified.

empty property ¤

empty: bool

Whether the node has neither modules nor packages.

Returns:

  • bool –

    True if empty, False otherwise.

enforce_init instance-attribute ¤

enforce_init: bool = enforce_init

Whether to enforce the presence of __init__.py files.

finder instance-attribute ¤

finder: Finder = Finder()

Finder instance for locating packages and modules.

isdsm property ¤

isdsm: bool

Inherited from NodeMixin. Always True.

Returns:

  • bool –

    Whether this object is a DSM.

ismodule property ¤

ismodule: bool

Property to check if object is instance of Module.

Returns:

  • bool –

    Whether this object is a module.

ispackage property ¤

ispackage: bool

Property to check if object is instance of Package.

Returns:

  • bool –

    Whether this object is a package.

modules instance-attribute ¤

modules: list[Module] = []

List of modules contained in the node.

not_found instance-attribute ¤

not_found: list[str] = []

List of packages that were not found.

packages instance-attribute ¤

packages: list[Package] = []

List of packages contained in the node.

specs instance-attribute ¤

List of package specifications found.

submodules property ¤

submodules: list[Module]

Property to return all sub-modules of the node, recursively.

Returns:

__bool__ ¤

__bool__() -> bool

Node as Boolean.

Returns:

  • bool –

    Result of node.empty.

Source code in src/dependenpy/_internal/node.py
124
125
126
127
128
129
130
def __bool__(self) -> bool:
    """Node as Boolean.

    Returns:
        Result of node.empty.
    """
    return bool(self.modules or self.packages)

__contains__ ¤

__contains__(item: Package | Module) -> bool

Get result of _contains, cache it and return it.

Parameters:

Returns:

  • bool –

    True if self contains item, False otherwise.

Source code in src/dependenpy/_internal/node.py
85
86
87
88
89
90
91
92
93
94
95
96
def __contains__(self, item: Package | Module) -> bool:
    """Get result of _contains, cache it and return it.

    Parameters:
        item: A package or module.

    Returns:
        True if self contains item, False otherwise.
    """
    if item not in self._contains_cache:
        self._contains_cache[item] = self._contains(item)
    return self._contains_cache[item]

__getitem__ ¤

__getitem__(item: str) -> Package | Module

Return the corresponding Package or Module object.

Parameters:

  • item ¤

    (str) –

    Name of the package/module, dot-separated.

Raises:

  • KeyError –

    When the package or module cannot be found.

Returns:

Source code in src/dependenpy/_internal/node.py
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
def __getitem__(self, item: str) -> Package | Module:
    """Return the corresponding Package or Module object.

    Parameters:
        item: Name of the package/module, dot-separated.

    Raises:
        KeyError: When the package or module cannot be found.

    Returns:
        The corresponding object.
    """
    depth = item.count(".") + 1
    parts = item.split(".", 1)
    for module in self.modules:
        if parts[0] == module.name and depth == 1:
            return module
    for package in self.packages:
        if parts[0] == package.name:
            if depth == 1:
                return package
            obj = package.get(parts[1])
            if obj:
                return obj
    raise KeyError(item)

as_dict ¤

as_dict() -> dict

Return the dependencies as a dictionary.

Returns:

  • dict –

    Dictionary of dependencies.

Source code in src/dependenpy/_internal/node.py
318
319
320
321
322
323
324
325
326
327
328
def as_dict(self) -> dict:
    """Return the dependencies as a dictionary.

    Returns:
        Dictionary of dependencies.
    """
    return {
        "name": str(self),
        "modules": [module.as_dict() for module in self.modules],
        "packages": [package.as_dict() for package in self.packages],
    }

as_graph ¤

as_graph(depth: int = 0) -> Graph

Create a graph with self as node, cache it, return it.

Parameters:

  • depth ¤

    (int, default: 0 ) –

    Depth of the graph.

Returns:

  • Graph –

    An instance of Graph.

Source code in src/dependenpy/_internal/node.py
330
331
332
333
334
335
336
337
338
339
340
341
def as_graph(self, depth: int = 0) -> Graph:
    """Create a graph with self as node, cache it, return it.

    Parameters:
        depth: Depth of the graph.

    Returns:
        An instance of Graph.
    """
    if depth not in self._graph_cache:
        self._graph_cache[depth] = Graph(self, depth=depth)  # ty:ignore[invalid-argument-type]
    return self._graph_cache[depth]

as_matrix ¤

as_matrix(depth: int = 0) -> Matrix

Create a matrix with self as node, cache it, return it.

Parameters:

  • depth ¤

    (int, default: 0 ) –

    Depth of the matrix.

Returns:

  • Matrix –

    An instance of Matrix.

Source code in src/dependenpy/_internal/node.py
343
344
345
346
347
348
349
350
351
352
353
354
def as_matrix(self, depth: int = 0) -> Matrix:
    """Create a matrix with self as node, cache it, return it.

    Parameters:
        depth: Depth of the matrix.

    Returns:
        An instance of Matrix.
    """
    if depth not in self._matrix_cache:
        self._matrix_cache[depth] = Matrix(self, depth=depth)  # ty:ignore[invalid-argument-type]
    return self._matrix_cache[depth]

as_treemap ¤

as_treemap() -> TreeMap

Return the dependencies as a TreeMap.

Returns:

  • TreeMap –

    An instance of TreeMap.

Source code in src/dependenpy/_internal/node.py
356
357
358
359
360
361
362
363
364
def as_treemap(self) -> TreeMap:
    """Return the dependencies as a TreeMap.

    Returns:
        An instance of TreeMap.
    """
    if not self._treemap_cache:
        self._treemap_cache = TreeMap(self)
    return self._treemap_cache

build_dependencies ¤

build_dependencies() -> None

Recursively build the dependencies for sub-modules and sub-packages.

Iterate on node's modules then packages and call their build_dependencies methods.

Source code in src/dependenpy/_internal/node.py
235
236
237
238
239
240
241
242
243
244
def build_dependencies(self) -> None:
    """Recursively build the dependencies for sub-modules and sub-packages.

    Iterate on node's modules then packages and call their
    build_dependencies methods.
    """
    for module in self.modules:
        module.build_dependencies()
    for package in self.packages:
        package.build_dependencies()

build_tree ¤

build_tree() -> None

Build the Python packages tree.

Source code in src/dependenpy/_internal/dsm.py
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
def build_tree(self) -> None:
    """Build the Python packages tree."""
    for spec in self.specs:
        if spec.ismodule:
            self.modules.append(Module(spec.name, spec.path, dsm=self))
        else:
            self.packages.append(
                Package(
                    spec.name,
                    spec.path,
                    dsm=self,
                    limit_to=spec.limit_to,
                    build_tree=True,
                    build_dependencies=False,
                    enforce_init=self.enforce_init,
                ),
            )

get ¤

get(item: str) -> Package | Module

Get item through __getitem__ and cache the result.

Parameters:

  • item ¤

    (str) –

    Name of package or module.

Returns:

Source code in src/dependenpy/_internal/node.py
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
def get(self, item: str) -> Package | Module:
    """Get item through `__getitem__` and cache the result.

    Parameters:
        item: Name of package or module.

    Returns:
        The corresponding object.
    """
    if item not in self._item_cache:
        try:
            obj = self.__getitem__(item)
        except KeyError:
            obj = None
        self._item_cache[item] = obj
    return self._item_cache[item]

get_target ¤

get_target(target: str) -> Package | Module

Get the result of _get_target, cache it and return it.

Parameters:

  • target ¤

    (str) –

    Target to find.

Returns:

  • Package | Module –

    Package containing target or corresponding module.

Source code in src/dependenpy/_internal/node.py
191
192
193
194
195
196
197
198
199
200
201
202
def get_target(self, target: str) -> Package | Module:
    """Get the result of _get_target, cache it and return it.

    Parameters:
        target: Target to find.

    Returns:
        Package containing target or corresponding module.
    """
    if target not in self._target_cache:
        self._target_cache[target] = self._get_target(target)
    return self._target_cache[target]

print ¤

print(
    format: str | None = TEXT,
    output: IO = stdout,
    **kwargs: Any,
) -> None

Print the object in a file or on standard output by default.

Parameters:

  • format ¤

    (str | None, default: TEXT ) –

    Output format (csv, json or text).

  • output ¤

    (IO, default: stdout ) –

    Descriptor to an opened file (default to standard output).

  • **kwargs ¤

    (Any, default: {} ) –

    Additional arguments.

Source code in src/dependenpy/_internal/helpers.py
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
def print(self, format: str | None = TEXT, output: IO = sys.stdout, **kwargs: Any) -> None:  # noqa: A002
    """Print the object in a file or on standard output by default.

    Parameters:
        format: Output format (csv, json or text).
        output: Descriptor to an opened file (default to standard output).
        **kwargs: Additional arguments.
    """
    if format is None:
        format = TEXT

    if format != TEXT:
        kwargs.pop("zero", "")

    if format == TEXT:
        print(self._to_text(**kwargs), file=output)
    elif format == CSV:
        print(self._to_csv(**kwargs), file=output)
    elif format == JSON:
        print(self._to_json(**kwargs), file=output)

print_graph ¤

print_graph(
    format: str | None = None,
    output: IO = stdout,
    depth: int = 0,
    **kwargs: Any,
) -> None

Print the graph for self's nodes.

Parameters:

  • format ¤

    (str | None, default: None ) –

    Output format (csv, json or text).

  • output ¤

    (IO, default: stdout ) –

    File descriptor on which to write.

  • depth ¤

    (int, default: 0 ) –

    Depth of the graph.

  • **kwargs ¤

    (Any, default: {} ) –

    Additional keyword arguments passed to graph.print.

Source code in src/dependenpy/_internal/node.py
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
def print_graph(
    self,
    format: str | None = None,  # noqa: A002
    output: IO = sys.stdout,
    depth: int = 0,
    **kwargs: Any,
) -> None:
    """Print the graph for self's nodes.

    Parameters:
        format: Output format (csv, json or text).
        output: File descriptor on which to write.
        depth: Depth of the graph.
        **kwargs: Additional keyword arguments passed to `graph.print`.
    """
    graph = self.as_graph(depth=depth)
    graph.print(format=format, output=output, **kwargs)

print_matrix ¤

print_matrix(
    format: str | None = None,
    output: IO = stdout,
    depth: int = 0,
    **kwargs: Any,
) -> None

Print the matrix for self's nodes.

Parameters:

  • format ¤

    (str | None, default: None ) –

    Output format (csv, json or text).

  • output ¤

    (IO, default: stdout ) –

    File descriptor on which to write.

  • depth ¤

    (int, default: 0 ) –

    Depth of the matrix.

  • **kwargs ¤

    (Any, default: {} ) –

    Additional keyword arguments passed to matrix.print.

Source code in src/dependenpy/_internal/node.py
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
def print_matrix(
    self,
    format: str | None = None,  # noqa: A002
    output: IO = sys.stdout,
    depth: int = 0,
    **kwargs: Any,
) -> None:
    """Print the matrix for self's nodes.

    Parameters:
        format: Output format (csv, json or text).
        output: File descriptor on which to write.
        depth: Depth of the matrix.
        **kwargs: Additional keyword arguments passed to `matrix.print`.
    """
    matrix = self.as_matrix(depth=depth)
    matrix.print(format=format, output=output, **kwargs)

print_treemap ¤

print_treemap(
    format: str | None = None,
    output: IO = stdout,
    **kwargs: Any,
) -> None

Print the matrix for self's nodes.

Parameters:

  • format ¤

    (str | None, default: None ) –

    Output format (csv, json or text).

  • output ¤

    (IO, default: stdout ) –

    File descriptor on which to write.

  • **kwargs ¤

    (Any, default: {} ) –

    Additional keyword arguments passed to treemap.print.

Source code in src/dependenpy/_internal/node.py
282
283
284
285
286
287
288
289
290
291
def print_treemap(self, format: str | None = None, output: IO = sys.stdout, **kwargs: Any) -> None:  # noqa: A002
    """Print the matrix for self's nodes.

    Parameters:
        format: Output format (csv, json or text).
        output: File descriptor on which to write.
        **kwargs: Additional keyword arguments passed to `treemap.print`.
    """
    treemap = self.as_treemap()
    treemap.print(format=format, output=output, **kwargs)

Dependency ¤

Dependency(
    source: Module,
    lineno: int,
    target: str | Module | Package,
    what: str | None = None,
)

Dependency class.

Represent a dependency from a module to another.

Parameters:

  • source ¤

    (Module) –

    Source Module.

  • lineno ¤

    (int) –

    Number of line at which import statement occurs.

  • target ¤

    (str | Module | Package) –

    The target node.

  • what ¤

    (str | None, default: None ) –

    What is imported (optional).

Attributes:

  • external (bool) –

    Property to tell if the dependency's target is a valid node.

  • lineno –

    Line number of the import statement.

  • source –

    Source module.

  • target –

    Target module or package.

  • what –

    What is imported (optional).

Source code in src/dependenpy/_internal/dsm.py
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
def __init__(self, source: Module, lineno: int, target: str | Module | Package, what: str | None = None) -> None:
    """Initialization method.

    Parameters:
        source: Source Module.
        lineno: Number of line at which import statement occurs.
        target: The target node.
        what: What is imported (optional).
    """
    self.source = source
    """Source module."""
    self.lineno = lineno
    """Line number of the import statement."""
    self.target = target
    """Target module or package."""
    self.what = what
    """What is imported (optional)."""

external property ¤

external: bool

Property to tell if the dependency's target is a valid node.

Returns:

  • bool –

    Whether the dependency's target is a valid node.

lineno instance-attribute ¤

lineno = lineno

Line number of the import statement.

source instance-attribute ¤

source = source

Source module.

target instance-attribute ¤

target = target

Target module or package.

what instance-attribute ¤

what = what

What is imported (optional).

Edge ¤

Edge class. Used in Graph class.

Parameters:

  • vertex_out ¤

    (Vertex) –

    source vertex (edge going out).

  • vertex_in ¤

    (Vertex) –

    target vertex (edge going in).

  • weight ¤

    (int, default: 1 ) –

    weight of the edge.

Methods:

  • go_from –

    Tell the edge to go out from this vertex.

  • go_in –

    Tell the edge to go into this vertex.

Attributes:

Source code in src/dependenpy/_internal/structures.py
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
def __init__(self, vertex_out: Vertex, vertex_in: Vertex, weight: int = 1) -> None:
    """Initialization method.

    Parameters:
        vertex_out (Vertex): source vertex (edge going out).
        vertex_in (Vertex): target vertex (edge going in).
        weight (int): weight of the edge.
    """
    self.vertex_out: Vertex | None = None
    """Outgoing vertex."""
    self.vertex_in: Vertex | None = None
    """Incoming vertex."""
    self.weight = weight
    """Weight of the edge."""
    self.go_from(vertex_out)
    self.go_in(vertex_in)

vertex_in instance-attribute ¤

vertex_in: Vertex | None = None

Incoming vertex.

vertex_out instance-attribute ¤

vertex_out: Vertex | None = None

Outgoing vertex.

weight instance-attribute ¤

weight = weight

Weight of the edge.

go_from ¤

go_from(vertex: Vertex) -> None

Tell the edge to go out from this vertex.

Parameters:

  • vertex ¤

    (Vertex) –

    vertex to go from.

Source code in src/dependenpy/_internal/structures.py
291
292
293
294
295
296
297
298
299
300
def go_from(self, vertex: Vertex) -> None:
    """Tell the edge to go out from this vertex.

    Parameters:
        vertex (Vertex): vertex to go from.
    """
    if self.vertex_out:
        self.vertex_out.edges_out.remove(self)
    self.vertex_out = vertex
    vertex.edges_out.add(self)

go_in ¤

go_in(vertex: Vertex) -> None

Tell the edge to go into this vertex.

Parameters:

  • vertex ¤

    (Vertex) –

    vertex to go into.

Source code in src/dependenpy/_internal/structures.py
302
303
304
305
306
307
308
309
310
311
def go_in(self, vertex: Vertex) -> None:
    """Tell the edge to go into this vertex.

    Parameters:
        vertex (Vertex): vertex to go into.
    """
    if self.vertex_in:
        self.vertex_in.edges_in.remove(self)
    self.vertex_in = vertex
    vertex.edges_in.add(self)

Finder ¤

Finder(finders: list[type] | None = None)

Main package finder class.

Initialize it with a list of package finder classes (not instances).

Parameters:

  • finders ¤

    (list[type] | None, default: None ) –

    list of package finder classes (not instances) in a specific order. Default: [LocalPackageFinder, InstalledPackageFinder].

Methods:

  • find –

    Find a package using package finders.

Attributes:

Source code in src/dependenpy/_internal/finder.py
171
172
173
174
175
176
177
178
179
180
181
182
183
184
def __init__(self, finders: list[type] | None = None):
    """Initialization method.

    Parameters:
        finders: list of package finder classes (not instances) in a specific
            order. Default: [LocalPackageFinder, InstalledPackageFinder].
    """
    self.finders: list[PackageFinder]
    """Selected finders."""
    if finders is None:
        finder_instances = [LocalPackageFinder(), InstalledPackageFinder()]
    else:
        finder_instances = [finder() for finder in finders]
    self.finders = finder_instances  # ty:ignore[invalid-assignment]

finders instance-attribute ¤

finders: list[PackageFinder] = finder_instances

Selected finders.

find ¤

find(package: str, **kwargs: Any) -> PackageSpec | None

Find a package using package finders.

Return the first package found.

Parameters:

  • package ¤

    (str) –

    package to find.

  • **kwargs ¤

    (Any, default: {} ) –

    additional keyword arguments used by finders.

Returns:

Source code in src/dependenpy/_internal/finder.py
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
def find(self, package: str, **kwargs: Any) -> PackageSpec | None:
    """Find a package using package finders.

    Return the first package found.

    Parameters:
        package: package to find.
        **kwargs: additional keyword arguments used by finders.

    Returns:
        Package spec or None.
    """
    for finder in self.finders:
        package_spec = finder.find(package, **kwargs)
        if package_spec:
            return package_spec
    return None

Graph ¤

Graph(*nodes: DSM | Package | Module, depth: int = 0)

Bases: PrintMixin

Graph class.

A class to build a graph given a list of nodes. After instantiation, it has two attributes: vertices, the set of nodes, and edges, the set of edges.

An intermediary matrix is built to ease the creation of the graph.

Parameters:

  • *nodes ¤

    (list of DSM/Package/Module, default: () ) –

    the nodes on which to build the graph.

  • depth ¤

    (int, default: 0 ) –

    the depth of the intermediary matrix. See the documentation for Matrix class.

Methods:

  • print –

    Print the object in a file or on standard output by default.

Attributes:

  • edges –

    Set of edges in the graph.

  • vertices –

    Set of vertices in the graph.

Source code in src/dependenpy/_internal/structures.py
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
def __init__(self, *nodes: DSM | Package | Module, depth: int = 0) -> None:
    """Initialization method.

    An intermediary matrix is built to ease the creation of the graph.

    Parameters:
        *nodes (list of DSM/Package/Module):
            the nodes on which to build the graph.
        depth (int): the depth of the intermediary matrix. See
            the documentation for Matrix class.
    """
    self.edges = set()
    """Set of edges in the graph."""
    vertices = []
    matrix = Matrix(*nodes, depth=depth)
    for key in matrix.keys:
        vertices.append(Vertex(key))  # noqa: PERF401
    for line_index, line in enumerate(matrix.data):
        for col_index, cell in enumerate(line):
            if cell > 0:
                self.edges.add(Edge(vertices[line_index], vertices[col_index], weight=cell))
    self.vertices = set(vertices)
    """Set of vertices in the graph."""

edges instance-attribute ¤

edges = set()

Set of edges in the graph.

vertices instance-attribute ¤

vertices = set(vertices)

Set of vertices in the graph.

print ¤

print(
    format: str | None = TEXT,
    output: IO = stdout,
    **kwargs: Any,
) -> None

Print the object in a file or on standard output by default.

Parameters:

  • format ¤

    (str | None, default: TEXT ) –

    Output format (csv, json or text).

  • output ¤

    (IO, default: stdout ) –

    Descriptor to an opened file (default to standard output).

  • **kwargs ¤

    (Any, default: {} ) –

    Additional arguments.

Source code in src/dependenpy/_internal/helpers.py
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
def print(self, format: str | None = TEXT, output: IO = sys.stdout, **kwargs: Any) -> None:  # noqa: A002
    """Print the object in a file or on standard output by default.

    Parameters:
        format: Output format (csv, json or text).
        output: Descriptor to an opened file (default to standard output).
        **kwargs: Additional arguments.
    """
    if format is None:
        format = TEXT

    if format != TEXT:
        kwargs.pop("zero", "")

    if format == TEXT:
        print(self._to_text(**kwargs), file=output)
    elif format == CSV:
        print(self._to_csv(**kwargs), file=output)
    elif format == JSON:
        print(self._to_json(**kwargs), file=output)

InstalledPackageFinder ¤

Bases: PackageFinder

Finder to find installed Python packages using importlib.

Methods:

  • find –

    Find method.

find ¤

find(package: str, **kwargs: Any) -> PackageSpec | None

Find method.

Parameters:

  • package ¤

    (str) –

    package to find.

  • **kwargs ¤

    (Any, default: {} ) –

    additional keyword arguments.

Returns:

Source code in src/dependenpy/_internal/finder.py
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
def find(self, package: str, **kwargs: Any) -> PackageSpec | None:  # noqa: ARG002
    """Find method.

    Parameters:
        package: package to find.
        **kwargs: additional keyword arguments.

    Returns:
        Package spec or None.
    """
    spec = find_spec(package)
    if spec is None:
        return None
    if "." in package:
        package, rest = package.split(".", 1)
        limit = [rest]
        spec = find_spec(package)
    else:
        limit = []
    if spec is not None:
        if spec.submodule_search_locations:
            path = spec.submodule_search_locations[0]
        elif spec.origin and spec.origin != "built-in":
            path = spec.origin
        else:
            return None
        return PackageSpec(spec.name, path, limit)
    return None

InternalDependencies ¤

Bases: Provider

Dependenpy provider for Archan.

Methods:

  • get_data –

    Provide matrix data for internal dependencies in a set of packages.

Attributes:

argument_list class-attribute instance-attribute ¤

argument_list = (
    archan.Argument(
        "packages",
        list,
        "The list of packages to check for.",
    ),
    archan.Argument(
        "enforce_init",
        bool,
        default=True,
        description="Whether to assert presence of __init__.py files in directories.",
    ),
    archan.Argument(
        "depth", int, "The depth of the matrix to generate."
    ),
)

List of arguments for the provider.

description class-attribute instance-attribute ¤

description = "Provide matrix data about internal dependencies in a set of packages."

Description of the provider.

identifier class-attribute instance-attribute ¤

identifier = 'dependenpy.InternalDependencies'

Identifier of the provider.

name class-attribute instance-attribute ¤

name = 'Internal Dependencies'

Name of the provider.

get_data ¤

get_data(
    packages: list[str],
    enforce_init: bool = True,
    depth: int | None = None,
) -> DSM

Provide matrix data for internal dependencies in a set of packages.

Parameters:

  • packages ¤

    (list[str]) –

    The list of packages to check for.

  • enforce_init ¤

    (bool, default: True ) –

    Whether to assert presence of init.py files in directories.

  • depth ¤

    (int | None, default: None ) –

    The depth of the matrix to generate.

Returns:

  • DSM –

    Instance of archan DSM.

Source code in src/dependenpy/_internal/plugins.py
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
def get_data(
    self,
    packages: list[str],
    enforce_init: bool = True,  # noqa: FBT001,FBT002
    depth: int | None = None,
) -> archan.DSM:
    """Provide matrix data for internal dependencies in a set of packages.

    Parameters:
        packages: The list of packages to check for.
        enforce_init: Whether to assert presence of __init__.py files in directories.
        depth: The depth of the matrix to generate.

    Returns:
        Instance of archan DSM.
    """
    dsm = DependenpyDSM(*packages, enforce_init=enforce_init)
    if depth is None:
        depth = guess_depth(packages)
    matrix = dsm.as_matrix(depth=depth)
    return archan.DesignStructureMatrix(data=matrix.data, entities=matrix.keys)

LeafNode ¤

LeafNode()

Shared code between Package and Module.

Methods:

Attributes:

  • depth (int) –

    Property to tell the depth of the node in the tree.

  • root (Package) –

    Property to return the root of this node.

Source code in src/dependenpy/_internal/node.py
370
371
372
def __init__(self):
    """Initialization method."""
    self._depth_cache = None

depth property ¤

depth: int

Property to tell the depth of the node in the tree.

Returns:

  • int –

    The node's depth in the tree.

root property ¤

root: Package

Property to return the root of this node.

Returns:

  • Package ( Package ) –

    this node's root package.

absolute_name ¤

absolute_name(depth: int = 0) -> str

Return the absolute name of the node.

Concatenate names from root to self within depth.

Parameters:

  • depth ¤

    (int, default: 0 ) –

    Maximum depth to go to.

Returns:

  • str –

    Absolute name of the node (until given depth is reached).

Source code in src/dependenpy/_internal/node.py
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
def absolute_name(self, depth: int = 0) -> str:
    """Return the absolute name of the node.

    Concatenate names from root to self within depth.

    Parameters:
        depth: Maximum depth to go to.

    Returns:
        Absolute name of the node (until given depth is reached).
    """
    node: Package
    node, node_depth = self, self.depth  # ty:ignore[invalid-assignment]
    if depth < 1:
        depth = node_depth
    while node_depth > depth and node.package is not None:
        node = node.package
        node_depth -= 1
    names = []
    while node is not None:
        names.append(node.name)
        node = node.package  # ty:ignore[invalid-assignment]
    return ".".join(reversed(names))

LocalPackageFinder ¤

Bases: PackageFinder

Finder to find local packages (directories on the disk).

Methods:

  • find –

    Find method.

find ¤

find(package: str, **kwargs: Any) -> PackageSpec | None

Find method.

Parameters:

  • package ¤

    (str) –

    Package to find.

  • **kwargs ¤

    (Any, default: {} ) –

    Additional keyword arguments.

Returns:

Source code in src/dependenpy/_internal/finder.py
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
def find(self, package: str, **kwargs: Any) -> PackageSpec | None:
    """Find method.

    Parameters:
        package: Package to find.
        **kwargs: Additional keyword arguments.

    Returns:
        Package spec or None.
    """
    if not exists(package):  # noqa: PTH110
        return None
    name, path = None, None
    enforce_init = kwargs.pop("enforce_init", True)
    if isdir(package):  # noqa: PTH112
        if isfile(join(package, "__init__.py")) or not enforce_init:  # noqa: PTH113, PTH118
            name, path = basename(package), package  # noqa: PTH119
    elif isfile(package) and package.endswith(".py"):  # noqa: PTH113
        name, path = splitext(basename(package))[0], package  # noqa: PTH119, PTH122
    if name and path:
        return PackageSpec(name, path)
    return None

Matrix ¤

Matrix(*nodes: DSM | Package | Module, depth: int = 0)

Bases: PrintMixin

Matrix class.

A class to build a matrix given a list of nodes. After instantiation, it has two attributes: data, a 2-dimensions array, and keys, the names of the entities in the corresponding order.

Parameters:

  • *nodes ¤

    (DSM | Package | Module, default: () ) –

    The nodes on which to build the matrix.

  • depth ¤

    (int, default: 0 ) –

    The depth of the matrix. This depth is always absolute, meaning that building a matrix with a sub-package "A.B.C" and a depth of 1 will return a matrix of size 1, containing A only. To see the matrix for the sub-modules and sub-packages in C, you will have to give depth=4.

Methods:

  • cast –

    Cast a set of keys and an array to a Matrix object.

  • print –

    Print the object in a file or on standard output by default.

Attributes:

  • data –

    The data of the matrix.

  • keys –

    The keys of the matrix.

  • size –

    The size of the matrix.

  • total (int) –

    Return the total number of dependencies within this matrix.

Source code in src/dependenpy/_internal/structures.py
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
def __init__(self, *nodes: DSM | Package | Module, depth: int = 0):
    """Initialization method.

    Parameters:
        *nodes: The nodes on which to build the matrix.
        depth: The depth of the matrix. This depth is always
            absolute, meaning that building a matrix with a sub-package
            "A.B.C" and a depth of 1 will return a matrix of size 1,
            containing A only. To see the matrix for the sub-modules and
            sub-packages in C, you will have to give depth=4.
    """
    modules: list[Module] = []
    for node in nodes:
        if node.ismodule:
            modules.append(node)  # ty:ignore[invalid-argument-type]
        elif node.ispackage or node.isdsm:
            modules.extend(node.submodules)  # ty:ignore[unresolved-attribute]

    if depth < 1:
        keys = modules
    else:
        keys = []
        for module in modules:
            if module.depth <= depth:
                keys.append(module)
                continue
            package = module.package
            while package.depth > depth and package.package and package not in nodes:  # ty:ignore[unresolved-attribute]
                package = package.package  # ty:ignore[unresolved-attribute]
            if package not in keys:
                keys.append(package)

    size = len(keys)
    data = [[0] * size for _ in range(size)]
    keys = sorted(keys, key=lambda key: key.absolute_name())  # ty:ignore[unresolved-attribute]

    if depth < 1:
        for index, key in enumerate(keys):
            key.index = index  # ty:ignore[invalid-assignment]
        for index, key in enumerate(keys):
            for dep in key.dependencies:  # ty:ignore[unresolved-attribute]
                if dep.external:
                    continue
                if dep.target.ismodule and dep.target in keys:  # ty:ignore[unresolved-attribute]
                    data[index][dep.target.index] += 1  # ty:ignore[unresolved-attribute]
                elif dep.target.ispackage:  # ty:ignore[unresolved-attribute]
                    init = dep.target.get("__init__")  # ty:ignore[unresolved-attribute]
                    if init is not None and init in keys:
                        data[index][init.index] += 1  # ty:ignore[unresolved-attribute]
    else:
        for row, row_key in enumerate(keys):
            for col, col_key in enumerate(keys):
                data[row][col] = row_key.cardinal(to=col_key)  # ty:ignore[invalid-argument-type,unresolved-attribute]

    self.size = size
    """The size of the matrix."""
    self.keys = [key.absolute_name() for key in keys]  # ty:ignore[unresolved-attribute]
    """The keys of the matrix."""
    self.data = data
    """The data of the matrix."""

data instance-attribute ¤

data = data

The data of the matrix.

keys instance-attribute ¤

keys = [key.absolute_name() for key in keys]

The keys of the matrix.

size instance-attribute ¤

size = size

The size of the matrix.

total property ¤

total: int

Return the total number of dependencies within this matrix.

Returns:

  • int –

    The total number of dependencies.

cast staticmethod ¤

cast(keys: list[str], data: list[list[int]]) -> Matrix

Cast a set of keys and an array to a Matrix object.

Parameters:

Returns:

Source code in src/dependenpy/_internal/structures.py
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
@staticmethod
def cast(keys: list[str], data: list[list[int]]) -> Matrix:
    """Cast a set of keys and an array to a Matrix object.

    Arguments:
        keys: The matrix keys.
        data: The matrix data.

    Returns:
        A new matrix.
    """
    matrix = Matrix()
    matrix.keys = copy.deepcopy(keys)
    matrix.data = copy.deepcopy(data)
    return matrix

print ¤

print(
    format: str | None = TEXT,
    output: IO = stdout,
    **kwargs: Any,
) -> None

Print the object in a file or on standard output by default.

Parameters:

  • format ¤

    (str | None, default: TEXT ) –

    Output format (csv, json or text).

  • output ¤

    (IO, default: stdout ) –

    Descriptor to an opened file (default to standard output).

  • **kwargs ¤

    (Any, default: {} ) –

    Additional arguments.

Source code in src/dependenpy/_internal/helpers.py
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
def print(self, format: str | None = TEXT, output: IO = sys.stdout, **kwargs: Any) -> None:  # noqa: A002
    """Print the object in a file or on standard output by default.

    Parameters:
        format: Output format (csv, json or text).
        output: Descriptor to an opened file (default to standard output).
        **kwargs: Additional arguments.
    """
    if format is None:
        format = TEXT

    if format != TEXT:
        kwargs.pop("zero", "")

    if format == TEXT:
        print(self._to_text(**kwargs), file=output)
    elif format == CSV:
        print(self._to_csv(**kwargs), file=output)
    elif format == JSON:
        print(self._to_json(**kwargs), file=output)

Module ¤

Module(
    name: str,
    path: str,
    dsm: DSM | None = None,
    package: Package | None = None,
)

Bases: LeafNode, NodeMixin, PrintMixin

Module class.

This class represents a Python module (a Python file).

Parameters:

  • name ¤

    (str) –

    Name of the module.

  • path ¤

    (str) –

    Path to the module.

  • dsm ¤

    (DSM | None, default: None ) –

    Parent DSM.

  • package ¤

    (Package | None, default: None ) –

    Parent Package.

Methods:

  • __contains__ –

    Whether given item is contained inside this module.

  • absolute_name –

    Return the absolute name of the node.

  • as_dict –

    Return the dependencies as a dictionary.

  • build_dependencies –

    Build the dependencies for this module.

  • cardinal –

    Return the number of dependencies of this module to the given node.

  • get_imports –

    Return all the import statements given an AST body (AST nodes).

  • parse_code –

    Read the source code and return all the import statements.

  • print –

    Print the object in a file or on standard output by default.

Attributes:

  • RECURSIVE_NODES –

    Nodes that can be recursive.

  • dependencies (list[Dependency]) –

    List of dependencies.

  • depth (int) –

    Property to tell the depth of the node in the tree.

  • dsm –

    Parent DSM.

  • isdsm (bool) –

    Property to check if object is instance of DSM.

  • ismodule (bool) –

    Inherited from NodeMixin. Always True.

  • ispackage (bool) –

    Property to check if object is instance of Package.

  • name –

    Name of the module.

  • package –

    Package to which the module belongs.

  • path –

    Path to the module.

  • root (Package) –

    Property to return the root of this node.

Source code in src/dependenpy/_internal/dsm.py
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
def __init__(self, name: str, path: str, dsm: DSM | None = None, package: Package | None = None) -> None:
    """Initialization method.

    Parameters:
        name: Name of the module.
        path: Path to the module.
        dsm: Parent DSM.
        package: Parent Package.
    """
    super().__init__()
    self.name = name
    """Name of the module."""
    self.path = path
    """Path to the module."""
    self.package = package
    """Package to which the module belongs."""
    self.dsm = dsm
    """Parent DSM."""
    self.dependencies: list[Dependency] = []
    """List of dependencies."""

RECURSIVE_NODES class-attribute instance-attribute ¤

Nodes that can be recursive.

dependencies instance-attribute ¤

dependencies: list[Dependency] = []

List of dependencies.

depth property ¤

depth: int

Property to tell the depth of the node in the tree.

Returns:

  • int –

    The node's depth in the tree.

dsm instance-attribute ¤

dsm = dsm

Parent DSM.

isdsm property ¤

isdsm: bool

Property to check if object is instance of DSM.

Returns:

  • bool –

    Whether this object is a DSM.

ismodule property ¤

ismodule: bool

Inherited from NodeMixin. Always True.

Returns:

  • bool –

    Whether this object is a module.

ispackage property ¤

ispackage: bool

Property to check if object is instance of Package.

Returns:

  • bool –

    Whether this object is a package.

name instance-attribute ¤

name = name

Name of the module.

package instance-attribute ¤

package = package

Package to which the module belongs.

path instance-attribute ¤

path = path

Path to the module.

root property ¤

root: Package

Property to return the root of this node.

Returns:

  • Package ( Package ) –

    this node's root package.

__contains__ ¤

__contains__(item: Package | Module) -> bool

Whether given item is contained inside this module.

Parameters:

Returns:

  • bool –

    True if self is item or item is self's package and self if an __init__ module.

Source code in src/dependenpy/_internal/dsm.py
292
293
294
295
296
297
298
299
300
301
302
303
304
def __contains__(self, item: Package | Module) -> bool:
    """Whether given item is contained inside this module.

    Parameters:
        item (Package/Module): a package or module.

    Returns:
        True if self is item or item is self's package and
            self if an `__init__` module.
    """
    if self is item:
        return True
    return self.package is item and self.name == "__init__"

absolute_name ¤

absolute_name(depth: int = 0) -> str

Return the absolute name of the node.

Concatenate names from root to self within depth.

Parameters:

  • depth ¤

    (int, default: 0 ) –

    Maximum depth to go to.

Returns:

  • str –

    Absolute name of the node (until given depth is reached).

Source code in src/dependenpy/_internal/node.py
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
def absolute_name(self, depth: int = 0) -> str:
    """Return the absolute name of the node.

    Concatenate names from root to self within depth.

    Parameters:
        depth: Maximum depth to go to.

    Returns:
        Absolute name of the node (until given depth is reached).
    """
    node: Package
    node, node_depth = self, self.depth  # ty:ignore[invalid-assignment]
    if depth < 1:
        depth = node_depth
    while node_depth > depth and node.package is not None:
        node = node.package
        node_depth -= 1
    names = []
    while node is not None:
        names.append(node.name)
        node = node.package  # ty:ignore[invalid-assignment]
    return ".".join(reversed(names))

as_dict ¤

as_dict(absolute: bool = False) -> dict

Return the dependencies as a dictionary.

Parameters:

  • absolute ¤

    (bool, default: False ) –

    Whether to use the absolute name.

Returns:

  • dict –

    Dictionary of dependencies.

Source code in src/dependenpy/_internal/dsm.py
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
def as_dict(self, absolute: bool = False) -> dict:  # noqa: FBT001,FBT002
    """Return the dependencies as a dictionary.

    Arguments:
        absolute: Whether to use the absolute name.

    Returns:
        Dictionary of dependencies.
    """
    return {
        "name": self.absolute_name() if absolute else self.name,
        "path": self.path,
        "dependencies": [
            {
                # 'source': d.source.absolute_name(),  # redundant
                "target": dep.target if dep.external else dep.target.absolute_name(),  # ty:ignore[unresolved-attribute]
                "lineno": dep.lineno,
                "what": dep.what,
                "external": dep.external,
            }
            for dep in self.dependencies
        ],
    }

build_dependencies ¤

build_dependencies() -> None

Build the dependencies for this module.

Parse the code with ast, find all the import statements, convert them into Dependency objects.

Source code in src/dependenpy/_internal/dsm.py
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
def build_dependencies(self) -> None:
    """Build the dependencies for this module.

    Parse the code with ast, find all the import statements, convert
    them into Dependency objects.
    """
    highest = self.dsm or self.root
    for import_ in self.parse_code():
        target = highest.get_target(import_["target"])
        if target:
            what = import_["target"].split(".")[-1]
            if what != target.name:
                import_["what"] = what
            import_["target"] = target
        self.dependencies.append(Dependency(source=self, **import_))

cardinal ¤

cardinal(to: Package | Module) -> int

Return the number of dependencies of this module to the given node.

Parameters:

Returns:

  • int –

    Number of dependencies.

Source code in src/dependenpy/_internal/dsm.py
423
424
425
426
427
428
429
430
431
432
def cardinal(self, to: Package | Module) -> int:
    """Return the number of dependencies of this module to the given node.

    Parameters:
        to: The target node.

    Returns:
        Number of dependencies.
    """
    return len([dep for dep in self.dependencies if not dep.external and dep.target in to])  # ty:ignore[unsupported-operator]

get_imports ¤

get_imports(ast_body: Sequence[AST]) -> list[dict]

Return all the import statements given an AST body (AST nodes).

Parameters:

Returns:

Source code in src/dependenpy/_internal/dsm.py
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
def get_imports(self, ast_body: Sequence[ast.AST]) -> list[dict]:
    """Return all the import statements given an AST body (AST nodes).

    Parameters:
        ast_body: The body to filter.

    Returns:
        The import statements.
    """
    imports: list[dict] = []
    for node in ast_body:
        if isinstance(node, ast.Import):
            imports.extend({"target": name.name, "lineno": node.lineno} for name in node.names)
        elif isinstance(node, ast.ImportFrom):
            for name in node.names:
                abs_name = self.absolute_name(self.depth - node.level) + "." if node.level > 0 else ""
                node_module = node.module + "." if node.module else ""
                name = abs_name + node_module + name.name  # noqa: PLW2901
                imports.append({"target": name, "lineno": node.lineno})
        elif isinstance(node, Module.RECURSIVE_NODES):
            imports.extend(self.get_imports(node.body))  # ty:ignore[invalid-argument-type]
            if isinstance(node, ast.Try):
                imports.extend(self.get_imports(node.finalbody))
    return imports

parse_code ¤

parse_code() -> list[dict]

Read the source code and return all the import statements.

Returns:

Source code in src/dependenpy/_internal/dsm.py
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
def parse_code(self) -> list[dict]:
    """Read the source code and return all the import statements.

    Returns:
        The import statements.
    """
    code = Path(self.path).read_text(encoding="utf-8")
    try:
        body = ast.parse(code).body
    except SyntaxError:
        code = code.encode("utf-8")
        try:
            body = ast.parse(code).body
        except SyntaxError:
            return []
    return self.get_imports(body)

print ¤

print(
    format: str | None = TEXT,
    output: IO = stdout,
    **kwargs: Any,
) -> None

Print the object in a file or on standard output by default.

Parameters:

  • format ¤

    (str | None, default: TEXT ) –

    Output format (csv, json or text).

  • output ¤

    (IO, default: stdout ) –

    Descriptor to an opened file (default to standard output).

  • **kwargs ¤

    (Any, default: {} ) –

    Additional arguments.

Source code in src/dependenpy/_internal/helpers.py
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
def print(self, format: str | None = TEXT, output: IO = sys.stdout, **kwargs: Any) -> None:  # noqa: A002
    """Print the object in a file or on standard output by default.

    Parameters:
        format: Output format (csv, json or text).
        output: Descriptor to an opened file (default to standard output).
        **kwargs: Additional arguments.
    """
    if format is None:
        format = TEXT

    if format != TEXT:
        kwargs.pop("zero", "")

    if format == TEXT:
        print(self._to_text(**kwargs), file=output)
    elif format == CSV:
        print(self._to_csv(**kwargs), file=output)
    elif format == JSON:
        print(self._to_json(**kwargs), file=output)

NodeMixin ¤

Shared code between DSM, Package and Module.

Attributes:

  • isdsm (bool) –

    Property to check if object is instance of DSM.

  • ismodule (bool) –

    Property to check if object is instance of Module.

  • ispackage (bool) –

    Property to check if object is instance of Package.

isdsm property ¤

isdsm: bool

Property to check if object is instance of DSM.

Returns:

  • bool –

    Whether this object is a DSM.

ismodule property ¤

ismodule: bool

Property to check if object is instance of Module.

Returns:

  • bool –

    Whether this object is a module.

ispackage property ¤

ispackage: bool

Property to check if object is instance of Package.

Returns:

  • bool –

    Whether this object is a package.

Package ¤

Package(
    name: str,
    path: str,
    dsm: DSM | None = None,
    package: Package | None = None,
    limit_to: list[str] | None = None,
    build_tree: bool = True,
    build_dependencies: bool = True,
    enforce_init: bool = True,
)

Bases: RootNode, LeafNode, NodeMixin, PrintMixin

Package class.

This class represent Python packages as nodes in a tree.

Parameters:

  • name ¤

    (str) –

    Name of the package.

  • path ¤

    (str) –

    Path to the package.

  • dsm ¤

    (DSM | None, default: None ) –

    Parent DSM.

  • package ¤

    (Package | None, default: None ) –

    Parent package.

  • limit_to ¤

    (list[str] | None, default: None ) –

    List of string to limit the recursive tree-building to what is specified.

  • build_tree ¤

    (bool, default: True ) –

    Auto-build the tree or not.

  • build_dependencies ¤

    (bool, default: True ) –

    Auto-build the dependencies or not.

  • enforce_init ¤

    (bool, default: True ) –

    If True, only treat directories if they contain an __init__.py file.

Methods:

  • __bool__ –

    Node as Boolean.

  • __contains__ –

    Get result of _contains, cache it and return it.

  • __getitem__ –

    Return the corresponding Package or Module object.

  • absolute_name –

    Return the absolute name of the node.

  • as_dict –

    Return the dependencies as a dictionary.

  • as_graph –

    Create a graph with self as node, cache it, return it.

  • as_matrix –

    Create a matrix with self as node, cache it, return it.

  • as_treemap –

    Return the dependencies as a TreeMap.

  • build_dependencies –

    Recursively build the dependencies for sub-modules and sub-packages.

  • build_tree –

    Build the tree for this package.

  • cardinal –

    Return the number of dependencies of this package to the given node.

  • get –

    Get item through __getitem__ and cache the result.

  • get_target –

    Get the result of _get_target, cache it and return it.

  • print –

    Print the object in a file or on standard output by default.

  • print_graph –

    Print the graph for self's nodes.

  • print_matrix –

    Print the matrix for self's nodes.

  • print_treemap –

    Print the matrix for self's nodes.

  • split_limits_heads –

    Return first parts of dot-separated strings, and rest of strings.

Attributes:

  • depth (int) –

    Property to tell the depth of the node in the tree.

  • dsm –

    Parent DSM.

  • empty (bool) –

    Whether the node has neither modules nor packages.

  • enforce_init –

    Whether to enforce the presence of __init__.py files.

  • isdsm (bool) –

    Property to check if object is instance of DSM.

  • ismodule (bool) –

    Property to check if object is instance of Module.

  • ispackage (bool) –

    Inherited from NodeMixin. Always True.

  • isroot (bool) –

    Property to tell if this node is a root node.

  • issubpackage (bool) –

    Property to tell if this node is a sub-package.

  • limit_to –

    List of strings to limit the recursive tree-building.

  • modules (list[Module]) –

    List of modules contained in the node.

  • name –

    Name of the package.

  • package –

    Parent package.

  • packages (list[Package]) –

    List of packages contained in the node.

  • path –

    Path to the package.

  • root (Package) –

    Property to return the root of this node.

  • submodules (list[Module]) –

    Property to return all sub-modules of the node, recursively.

Source code in src/dependenpy/_internal/dsm.py
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
def __init__(  # noqa: PLR0917
    self,
    name: str,
    path: str,
    dsm: DSM | None = None,
    package: Package | None = None,
    limit_to: list[str] | None = None,
    build_tree: bool = True,  # noqa: FBT001,FBT002
    build_dependencies: bool = True,  # noqa: FBT001,FBT002
    enforce_init: bool = True,  # noqa: FBT001,FBT002
):
    """Initialization method.

    Parameters:
        name: Name of the package.
        path: Path to the package.
        dsm: Parent DSM.
        package: Parent package.
        limit_to: List of string to limit the recursive tree-building to what is specified.
        build_tree: Auto-build the tree or not.
        build_dependencies: Auto-build the dependencies or not.
        enforce_init: If True, only treat directories if they contain an `__init__.py` file.
    """
    self.name = name
    """Name of the package."""
    self.path = path
    """Path to the package."""
    self.package = package
    """Parent package."""
    self.dsm = dsm
    """Parent DSM."""
    self.limit_to = limit_to or []
    """List of strings to limit the recursive tree-building."""
    self.enforce_init = enforce_init
    """Whether to enforce the presence of `__init__.py` files."""

    RootNode.__init__(self, build_tree)
    LeafNode.__init__(self)

    if build_tree and build_dependencies:
        self.build_dependencies()

depth property ¤

depth: int

Property to tell the depth of the node in the tree.

Returns:

  • int –

    The node's depth in the tree.

dsm instance-attribute ¤

dsm = dsm

Parent DSM.

empty property ¤

empty: bool

Whether the node has neither modules nor packages.

Returns:

  • bool –

    True if empty, False otherwise.

enforce_init instance-attribute ¤

enforce_init = enforce_init

Whether to enforce the presence of __init__.py files.

isdsm property ¤

isdsm: bool

Property to check if object is instance of DSM.

Returns:

  • bool –

    Whether this object is a DSM.

ismodule property ¤

ismodule: bool

Property to check if object is instance of Module.

Returns:

  • bool –

    Whether this object is a module.

ispackage property ¤

ispackage: bool

Inherited from NodeMixin. Always True.

Returns:

  • bool –

    Whether this object is a package.

isroot property ¤

isroot: bool

Property to tell if this node is a root node.

Returns:

  • bool –

    This package has no parent.

issubpackage property ¤

issubpackage: bool

Property to tell if this node is a sub-package.

Returns:

  • bool –

    This package has a parent.

limit_to instance-attribute ¤

limit_to = limit_to or []

List of strings to limit the recursive tree-building.

modules instance-attribute ¤

modules: list[Module] = []

List of modules contained in the node.

name instance-attribute ¤

name = name

Name of the package.

package instance-attribute ¤

package = package

Parent package.

packages instance-attribute ¤

packages: list[Package] = []

List of packages contained in the node.

path instance-attribute ¤

path = path

Path to the package.

root property ¤

root: Package

Property to return the root of this node.

Returns:

  • Package ( Package ) –

    this node's root package.

submodules property ¤

submodules: list[Module]

Property to return all sub-modules of the node, recursively.

Returns:

__bool__ ¤

__bool__() -> bool

Node as Boolean.

Returns:

  • bool –

    Result of node.empty.

Source code in src/dependenpy/_internal/node.py
124
125
126
127
128
129
130
def __bool__(self) -> bool:
    """Node as Boolean.

    Returns:
        Result of node.empty.
    """
    return bool(self.modules or self.packages)

__contains__ ¤

__contains__(item: Package | Module) -> bool

Get result of _contains, cache it and return it.

Parameters:

Returns:

  • bool –

    True if self contains item, False otherwise.

Source code in src/dependenpy/_internal/node.py
85
86
87
88
89
90
91
92
93
94
95
96
def __contains__(self, item: Package | Module) -> bool:
    """Get result of _contains, cache it and return it.

    Parameters:
        item: A package or module.

    Returns:
        True if self contains item, False otherwise.
    """
    if item not in self._contains_cache:
        self._contains_cache[item] = self._contains(item)
    return self._contains_cache[item]

__getitem__ ¤

__getitem__(item: str) -> Package | Module

Return the corresponding Package or Module object.

Parameters:

  • item ¤

    (str) –

    Name of the package/module, dot-separated.

Raises:

  • KeyError –

    When the package or module cannot be found.

Returns:

Source code in src/dependenpy/_internal/node.py
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
def __getitem__(self, item: str) -> Package | Module:
    """Return the corresponding Package or Module object.

    Parameters:
        item: Name of the package/module, dot-separated.

    Raises:
        KeyError: When the package or module cannot be found.

    Returns:
        The corresponding object.
    """
    depth = item.count(".") + 1
    parts = item.split(".", 1)
    for module in self.modules:
        if parts[0] == module.name and depth == 1:
            return module
    for package in self.packages:
        if parts[0] == package.name:
            if depth == 1:
                return package
            obj = package.get(parts[1])
            if obj:
                return obj
    raise KeyError(item)

absolute_name ¤

absolute_name(depth: int = 0) -> str

Return the absolute name of the node.

Concatenate names from root to self within depth.

Parameters:

  • depth ¤

    (int, default: 0 ) –

    Maximum depth to go to.

Returns:

  • str –

    Absolute name of the node (until given depth is reached).

Source code in src/dependenpy/_internal/node.py
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
def absolute_name(self, depth: int = 0) -> str:
    """Return the absolute name of the node.

    Concatenate names from root to self within depth.

    Parameters:
        depth: Maximum depth to go to.

    Returns:
        Absolute name of the node (until given depth is reached).
    """
    node: Package
    node, node_depth = self, self.depth  # ty:ignore[invalid-assignment]
    if depth < 1:
        depth = node_depth
    while node_depth > depth and node.package is not None:
        node = node.package
        node_depth -= 1
    names = []
    while node is not None:
        names.append(node.name)
        node = node.package  # ty:ignore[invalid-assignment]
    return ".".join(reversed(names))

as_dict ¤

as_dict() -> dict

Return the dependencies as a dictionary.

Returns:

  • dict –

    Dictionary of dependencies.

Source code in src/dependenpy/_internal/node.py
318
319
320
321
322
323
324
325
326
327
328
def as_dict(self) -> dict:
    """Return the dependencies as a dictionary.

    Returns:
        Dictionary of dependencies.
    """
    return {
        "name": str(self),
        "modules": [module.as_dict() for module in self.modules],
        "packages": [package.as_dict() for package in self.packages],
    }

as_graph ¤

as_graph(depth: int = 0) -> Graph

Create a graph with self as node, cache it, return it.

Parameters:

  • depth ¤

    (int, default: 0 ) –

    Depth of the graph.

Returns:

  • Graph –

    An instance of Graph.

Source code in src/dependenpy/_internal/node.py
330
331
332
333
334
335
336
337
338
339
340
341
def as_graph(self, depth: int = 0) -> Graph:
    """Create a graph with self as node, cache it, return it.

    Parameters:
        depth: Depth of the graph.

    Returns:
        An instance of Graph.
    """
    if depth not in self._graph_cache:
        self._graph_cache[depth] = Graph(self, depth=depth)  # ty:ignore[invalid-argument-type]
    return self._graph_cache[depth]

as_matrix ¤

as_matrix(depth: int = 0) -> Matrix

Create a matrix with self as node, cache it, return it.

Parameters:

  • depth ¤

    (int, default: 0 ) –

    Depth of the matrix.

Returns:

  • Matrix –

    An instance of Matrix.

Source code in src/dependenpy/_internal/node.py
343
344
345
346
347
348
349
350
351
352
353
354
def as_matrix(self, depth: int = 0) -> Matrix:
    """Create a matrix with self as node, cache it, return it.

    Parameters:
        depth: Depth of the matrix.

    Returns:
        An instance of Matrix.
    """
    if depth not in self._matrix_cache:
        self._matrix_cache[depth] = Matrix(self, depth=depth)  # ty:ignore[invalid-argument-type]
    return self._matrix_cache[depth]

as_treemap ¤

as_treemap() -> TreeMap

Return the dependencies as a TreeMap.

Returns:

  • TreeMap –

    An instance of TreeMap.

Source code in src/dependenpy/_internal/node.py
356
357
358
359
360
361
362
363
364
def as_treemap(self) -> TreeMap:
    """Return the dependencies as a TreeMap.

    Returns:
        An instance of TreeMap.
    """
    if not self._treemap_cache:
        self._treemap_cache = TreeMap(self)
    return self._treemap_cache

build_dependencies ¤

build_dependencies() -> None

Recursively build the dependencies for sub-modules and sub-packages.

Iterate on node's modules then packages and call their build_dependencies methods.

Source code in src/dependenpy/_internal/node.py
235
236
237
238
239
240
241
242
243
244
def build_dependencies(self) -> None:
    """Recursively build the dependencies for sub-modules and sub-packages.

    Iterate on node's modules then packages and call their
    build_dependencies methods.
    """
    for module in self.modules:
        module.build_dependencies()
    for package in self.packages:
        package.build_dependencies()

build_tree ¤

build_tree() -> None

Build the tree for this package.

Source code in src/dependenpy/_internal/dsm.py
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
def build_tree(self) -> None:
    """Build the tree for this package."""
    for module in listdir(self.path):  # noqa: PTH208
        abs_m = join(self.path, module)  # noqa: PTH118
        if isfile(abs_m) and module.endswith(".py"):  # noqa: PTH113
            name = splitext(module)[0]  # noqa: PTH122
            if not self.limit_to or name in self.limit_to:
                self.modules.append(Module(name, abs_m, self.dsm, self))
        elif isdir(abs_m) and (isfile(join(abs_m, "__init__.py")) or not self.enforce_init):  # noqa: PTH112, PTH113, PTH118
            heads, new_limit_to = self.split_limits_heads()
            if not heads or module in heads:
                self.packages.append(
                    Package(
                        module,
                        abs_m,
                        self.dsm,
                        self,
                        new_limit_to,
                        build_tree=True,
                        build_dependencies=False,
                        enforce_init=self.enforce_init,
                    ),
                )

cardinal ¤

cardinal(to: Package | Module) -> int

Return the number of dependencies of this package to the given node.

Parameters:

Returns:

  • int –

    Number of dependencies.

Source code in src/dependenpy/_internal/dsm.py
250
251
252
253
254
255
256
257
258
259
def cardinal(self, to: Package | Module) -> int:
    """Return the number of dependencies of this package to the given node.

    Parameters:
        to: Target node.

    Returns:
        Number of dependencies.
    """
    return sum(module.cardinal(to) for module in self.submodules)

get ¤

get(item: str) -> Package | Module

Get item through __getitem__ and cache the result.

Parameters:

  • item ¤

    (str) –

    Name of package or module.

Returns:

Source code in src/dependenpy/_internal/node.py
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
def get(self, item: str) -> Package | Module:
    """Get item through `__getitem__` and cache the result.

    Parameters:
        item: Name of package or module.

    Returns:
        The corresponding object.
    """
    if item not in self._item_cache:
        try:
            obj = self.__getitem__(item)
        except KeyError:
            obj = None
        self._item_cache[item] = obj
    return self._item_cache[item]

get_target ¤

get_target(target: str) -> Package | Module

Get the result of _get_target, cache it and return it.

Parameters:

  • target ¤

    (str) –

    Target to find.

Returns:

  • Package | Module –

    Package containing target or corresponding module.

Source code in src/dependenpy/_internal/node.py
191
192
193
194
195
196
197
198
199
200
201
202
def get_target(self, target: str) -> Package | Module:
    """Get the result of _get_target, cache it and return it.

    Parameters:
        target: Target to find.

    Returns:
        Package containing target or corresponding module.
    """
    if target not in self._target_cache:
        self._target_cache[target] = self._get_target(target)
    return self._target_cache[target]

print ¤

print(
    format: str | None = TEXT,
    output: IO = stdout,
    **kwargs: Any,
) -> None

Print the object in a file or on standard output by default.

Parameters:

  • format ¤

    (str | None, default: TEXT ) –

    Output format (csv, json or text).

  • output ¤

    (IO, default: stdout ) –

    Descriptor to an opened file (default to standard output).

  • **kwargs ¤

    (Any, default: {} ) –

    Additional arguments.

Source code in src/dependenpy/_internal/helpers.py
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
def print(self, format: str | None = TEXT, output: IO = sys.stdout, **kwargs: Any) -> None:  # noqa: A002
    """Print the object in a file or on standard output by default.

    Parameters:
        format: Output format (csv, json or text).
        output: Descriptor to an opened file (default to standard output).
        **kwargs: Additional arguments.
    """
    if format is None:
        format = TEXT

    if format != TEXT:
        kwargs.pop("zero", "")

    if format == TEXT:
        print(self._to_text(**kwargs), file=output)
    elif format == CSV:
        print(self._to_csv(**kwargs), file=output)
    elif format == JSON:
        print(self._to_json(**kwargs), file=output)

print_graph ¤

print_graph(
    format: str | None = None,
    output: IO = stdout,
    depth: int = 0,
    **kwargs: Any,
) -> None

Print the graph for self's nodes.

Parameters:

  • format ¤

    (str | None, default: None ) –

    Output format (csv, json or text).

  • output ¤

    (IO, default: stdout ) –

    File descriptor on which to write.

  • depth ¤

    (int, default: 0 ) –

    Depth of the graph.

  • **kwargs ¤

    (Any, default: {} ) –

    Additional keyword arguments passed to graph.print.

Source code in src/dependenpy/_internal/node.py
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
def print_graph(
    self,
    format: str | None = None,  # noqa: A002
    output: IO = sys.stdout,
    depth: int = 0,
    **kwargs: Any,
) -> None:
    """Print the graph for self's nodes.

    Parameters:
        format: Output format (csv, json or text).
        output: File descriptor on which to write.
        depth: Depth of the graph.
        **kwargs: Additional keyword arguments passed to `graph.print`.
    """
    graph = self.as_graph(depth=depth)
    graph.print(format=format, output=output, **kwargs)

print_matrix ¤

print_matrix(
    format: str | None = None,
    output: IO = stdout,
    depth: int = 0,
    **kwargs: Any,
) -> None

Print the matrix for self's nodes.

Parameters:

  • format ¤

    (str | None, default: None ) –

    Output format (csv, json or text).

  • output ¤

    (IO, default: stdout ) –

    File descriptor on which to write.

  • depth ¤

    (int, default: 0 ) –

    Depth of the matrix.

  • **kwargs ¤

    (Any, default: {} ) –

    Additional keyword arguments passed to matrix.print.

Source code in src/dependenpy/_internal/node.py
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
def print_matrix(
    self,
    format: str | None = None,  # noqa: A002
    output: IO = sys.stdout,
    depth: int = 0,
    **kwargs: Any,
) -> None:
    """Print the matrix for self's nodes.

    Parameters:
        format: Output format (csv, json or text).
        output: File descriptor on which to write.
        depth: Depth of the matrix.
        **kwargs: Additional keyword arguments passed to `matrix.print`.
    """
    matrix = self.as_matrix(depth=depth)
    matrix.print(format=format, output=output, **kwargs)

print_treemap ¤

print_treemap(
    format: str | None = None,
    output: IO = stdout,
    **kwargs: Any,
) -> None

Print the matrix for self's nodes.

Parameters:

  • format ¤

    (str | None, default: None ) –

    Output format (csv, json or text).

  • output ¤

    (IO, default: stdout ) –

    File descriptor on which to write.

  • **kwargs ¤

    (Any, default: {} ) –

    Additional keyword arguments passed to treemap.print.

Source code in src/dependenpy/_internal/node.py
282
283
284
285
286
287
288
289
290
291
def print_treemap(self, format: str | None = None, output: IO = sys.stdout, **kwargs: Any) -> None:  # noqa: A002
    """Print the matrix for self's nodes.

    Parameters:
        format: Output format (csv, json or text).
        output: File descriptor on which to write.
        **kwargs: Additional keyword arguments passed to `treemap.print`.
    """
    treemap = self.as_treemap()
    treemap.print(format=format, output=output, **kwargs)

split_limits_heads ¤

split_limits_heads() -> tuple[list[str], list[str]]

Return first parts of dot-separated strings, and rest of strings.

Returns:

Source code in src/dependenpy/_internal/dsm.py
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
def split_limits_heads(self) -> tuple[list[str], list[str]]:
    """Return first parts of dot-separated strings, and rest of strings.

    Returns:
        The heads and rest of the strings.
    """
    heads = []
    new_limit_to = []
    for limit in self.limit_to:
        if "." in limit:
            name, limit = limit.split(".", 1)  # noqa: PLW2901
            heads.append(name)
            new_limit_to.append(limit)
        else:
            heads.append(limit)
    return heads, new_limit_to

PackageFinder ¤

Abstract package finder class.

Methods:

  • find –

    Find method.

find ¤

find(package: str, **kwargs: Any) -> PackageSpec | None

Find method.

Parameters:

  • package ¤

    (str) –

    Package to find.

  • **kwargs ¤

    (Any, default: {} ) –

    Additional keyword arguments.

Returns:

Source code in src/dependenpy/_internal/finder.py
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
def find(self, package: str, **kwargs: Any) -> PackageSpec | None:
    """Find method.

    Parameters:
        package: Package to find.
        **kwargs: Additional keyword arguments.

    Returns:
        Package spec or None.
    """
    raise NotImplementedError

PackageSpec ¤

PackageSpec(
    name: str, path: str, limit_to: list[str] | None = None
)

Holder for a package specification (given as argument to DSM).

Parameters:

  • name ¤

    (str) –

    Name of the package.

  • path ¤

    (str) –

    Path to the package.

  • limit_to ¤

    (list[str] | None, default: None ) –

    Limitations.

Methods:

  • __hash__ –

    Hash method.

  • add –

    Add limitations of given spec to self's.

  • combine –

    Combine package specifications' limitations.

Attributes:

  • ismodule (bool) –

    Property to tell if the package is in fact a module (a file).

  • limit_to –

    List of limitations.

  • name –

    Name of the package.

  • path –

    Path to the package.

Source code in src/dependenpy/_internal/finder.py
29
30
31
32
33
34
35
36
37
38
39
40
41
42
def __init__(self, name: str, path: str, limit_to: list[str] | None = None) -> None:
    """Initialization method.

    Parameters:
        name: Name of the package.
        path: Path to the package.
        limit_to: Limitations.
    """
    self.name = name
    """Name of the package."""
    self.path = path
    """Path to the package."""
    self.limit_to = limit_to or []
    """List of limitations."""

ismodule property ¤

ismodule: bool

Property to tell if the package is in fact a module (a file).

Returns:

  • bool –

    Whether this package is in fact a module.

limit_to instance-attribute ¤

limit_to = limit_to or []

List of limitations.

name instance-attribute ¤

name = name

Name of the package.

path instance-attribute ¤

path = path

Path to the package.

__hash__ ¤

__hash__()

Hash method.

The hash is computed based on the package name and path.

Source code in src/dependenpy/_internal/finder.py
44
45
46
47
48
49
def __hash__(self):
    """Hash method.

    The hash is computed based on the package name and path.
    """
    return hash((self.name, self.path))

add ¤

add(spec: PackageSpec) -> None

Add limitations of given spec to self's.

Parameters:

Source code in src/dependenpy/_internal/finder.py
60
61
62
63
64
65
66
67
68
def add(self, spec: PackageSpec) -> None:
    """Add limitations of given spec to self's.

    Parameters:
        spec: Another spec.
    """
    for limit in spec.limit_to:
        if limit not in self.limit_to:
            self.limit_to.append(limit)

combine staticmethod ¤

Combine package specifications' limitations.

Parameters:

Returns:

Source code in src/dependenpy/_internal/finder.py
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
@staticmethod
def combine(specs: list[PackageSpec]) -> list[PackageSpec]:
    """Combine package specifications' limitations.

    Parameters:
        specs: The package specifications.

    Returns:
        The new, merged list of PackageSpec.
    """
    new_specs: dict[PackageSpec, PackageSpec] = {}
    for spec in specs:
        if new_specs.get(spec) is None:
            new_specs[spec] = spec
        else:
            new_specs[spec].add(spec)
    return list(new_specs.values())

PrintMixin ¤

Print mixin class.

Methods:

  • print –

    Print the object in a file or on standard output by default.

print ¤

print(
    format: str | None = TEXT,
    output: IO = stdout,
    **kwargs: Any,
) -> None

Print the object in a file or on standard output by default.

Parameters:

  • format ¤

    (str | None, default: TEXT ) –

    Output format (csv, json or text).

  • output ¤

    (IO, default: stdout ) –

    Descriptor to an opened file (default to standard output).

  • **kwargs ¤

    (Any, default: {} ) –

    Additional arguments.

Source code in src/dependenpy/_internal/helpers.py
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
def print(self, format: str | None = TEXT, output: IO = sys.stdout, **kwargs: Any) -> None:  # noqa: A002
    """Print the object in a file or on standard output by default.

    Parameters:
        format: Output format (csv, json or text).
        output: Descriptor to an opened file (default to standard output).
        **kwargs: Additional arguments.
    """
    if format is None:
        format = TEXT

    if format != TEXT:
        kwargs.pop("zero", "")

    if format == TEXT:
        print(self._to_text(**kwargs), file=output)
    elif format == CSV:
        print(self._to_csv(**kwargs), file=output)
    elif format == JSON:
        print(self._to_json(**kwargs), file=output)

RootNode ¤

RootNode(build_tree: bool = True)

Shared code between DSM and Package.

Parameters:

  • build_tree ¤

    (bool, default: True ) –

    Whether to immediately build the tree or not.

Methods:

  • __bool__ –

    Node as Boolean.

  • __contains__ –

    Get result of _contains, cache it and return it.

  • __getitem__ –

    Return the corresponding Package or Module object.

  • as_dict –

    Return the dependencies as a dictionary.

  • as_graph –

    Create a graph with self as node, cache it, return it.

  • as_matrix –

    Create a matrix with self as node, cache it, return it.

  • as_treemap –

    Return the dependencies as a TreeMap.

  • build_dependencies –

    Recursively build the dependencies for sub-modules and sub-packages.

  • build_tree –

    To be overridden.

  • get –

    Get item through __getitem__ and cache the result.

  • get_target –

    Get the result of _get_target, cache it and return it.

  • print_graph –

    Print the graph for self's nodes.

  • print_matrix –

    Print the matrix for self's nodes.

  • print_treemap –

    Print the matrix for self's nodes.

Attributes:

Source code in src/dependenpy/_internal/node.py
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
def __init__(self, build_tree: bool = True):  # noqa: FBT001,FBT002
    """Initialization method.

    Parameters:
        build_tree: Whether to immediately build the tree or not.
    """
    self._target_cache: dict[str, Any] = {}
    self._item_cache: dict[str, Any] = {}
    self._contains_cache: dict[Package | Module, bool] = {}
    self._matrix_cache: dict[int, Matrix] = {}
    self._graph_cache: dict[int, Graph] = {}
    self._treemap_cache = TreeMap()
    self.modules: list[Module] = []
    """List of modules contained in the node."""
    self.packages: list[Package] = []
    """List of packages contained in the node."""

    if build_tree:
        self.build_tree()

empty property ¤

empty: bool

Whether the node has neither modules nor packages.

Returns:

  • bool –

    True if empty, False otherwise.

modules instance-attribute ¤

modules: list[Module] = []

List of modules contained in the node.

packages instance-attribute ¤

packages: list[Package] = []

List of packages contained in the node.

submodules property ¤

submodules: list[Module]

Property to return all sub-modules of the node, recursively.

Returns:

__bool__ ¤

__bool__() -> bool

Node as Boolean.

Returns:

  • bool –

    Result of node.empty.

Source code in src/dependenpy/_internal/node.py
124
125
126
127
128
129
130
def __bool__(self) -> bool:
    """Node as Boolean.

    Returns:
        Result of node.empty.
    """
    return bool(self.modules or self.packages)

__contains__ ¤

__contains__(item: Package | Module) -> bool

Get result of _contains, cache it and return it.

Parameters:

Returns:

  • bool –

    True if self contains item, False otherwise.

Source code in src/dependenpy/_internal/node.py
85
86
87
88
89
90
91
92
93
94
95
96
def __contains__(self, item: Package | Module) -> bool:
    """Get result of _contains, cache it and return it.

    Parameters:
        item: A package or module.

    Returns:
        True if self contains item, False otherwise.
    """
    if item not in self._contains_cache:
        self._contains_cache[item] = self._contains(item)
    return self._contains_cache[item]

__getitem__ ¤

__getitem__(item: str) -> Package | Module

Return the corresponding Package or Module object.

Parameters:

  • item ¤

    (str) –

    Name of the package/module, dot-separated.

Raises:

  • KeyError –

    When the package or module cannot be found.

Returns:

Source code in src/dependenpy/_internal/node.py
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
def __getitem__(self, item: str) -> Package | Module:
    """Return the corresponding Package or Module object.

    Parameters:
        item: Name of the package/module, dot-separated.

    Raises:
        KeyError: When the package or module cannot be found.

    Returns:
        The corresponding object.
    """
    depth = item.count(".") + 1
    parts = item.split(".", 1)
    for module in self.modules:
        if parts[0] == module.name and depth == 1:
            return module
    for package in self.packages:
        if parts[0] == package.name:
            if depth == 1:
                return package
            obj = package.get(parts[1])
            if obj:
                return obj
    raise KeyError(item)

as_dict ¤

as_dict() -> dict

Return the dependencies as a dictionary.

Returns:

  • dict –

    Dictionary of dependencies.

Source code in src/dependenpy/_internal/node.py
318
319
320
321
322
323
324
325
326
327
328
def as_dict(self) -> dict:
    """Return the dependencies as a dictionary.

    Returns:
        Dictionary of dependencies.
    """
    return {
        "name": str(self),
        "modules": [module.as_dict() for module in self.modules],
        "packages": [package.as_dict() for package in self.packages],
    }

as_graph ¤

as_graph(depth: int = 0) -> Graph

Create a graph with self as node, cache it, return it.

Parameters:

  • depth ¤

    (int, default: 0 ) –

    Depth of the graph.

Returns:

  • Graph –

    An instance of Graph.

Source code in src/dependenpy/_internal/node.py
330
331
332
333
334
335
336
337
338
339
340
341
def as_graph(self, depth: int = 0) -> Graph:
    """Create a graph with self as node, cache it, return it.

    Parameters:
        depth: Depth of the graph.

    Returns:
        An instance of Graph.
    """
    if depth not in self._graph_cache:
        self._graph_cache[depth] = Graph(self, depth=depth)  # ty:ignore[invalid-argument-type]
    return self._graph_cache[depth]

as_matrix ¤

as_matrix(depth: int = 0) -> Matrix

Create a matrix with self as node, cache it, return it.

Parameters:

  • depth ¤

    (int, default: 0 ) –

    Depth of the matrix.

Returns:

  • Matrix –

    An instance of Matrix.

Source code in src/dependenpy/_internal/node.py
343
344
345
346
347
348
349
350
351
352
353
354
def as_matrix(self, depth: int = 0) -> Matrix:
    """Create a matrix with self as node, cache it, return it.

    Parameters:
        depth: Depth of the matrix.

    Returns:
        An instance of Matrix.
    """
    if depth not in self._matrix_cache:
        self._matrix_cache[depth] = Matrix(self, depth=depth)  # ty:ignore[invalid-argument-type]
    return self._matrix_cache[depth]

as_treemap ¤

as_treemap() -> TreeMap

Return the dependencies as a TreeMap.

Returns:

  • TreeMap –

    An instance of TreeMap.

Source code in src/dependenpy/_internal/node.py
356
357
358
359
360
361
362
363
364
def as_treemap(self) -> TreeMap:
    """Return the dependencies as a TreeMap.

    Returns:
        An instance of TreeMap.
    """
    if not self._treemap_cache:
        self._treemap_cache = TreeMap(self)
    return self._treemap_cache

build_dependencies ¤

build_dependencies() -> None

Recursively build the dependencies for sub-modules and sub-packages.

Iterate on node's modules then packages and call their build_dependencies methods.

Source code in src/dependenpy/_internal/node.py
235
236
237
238
239
240
241
242
243
244
def build_dependencies(self) -> None:
    """Recursively build the dependencies for sub-modules and sub-packages.

    Iterate on node's modules then packages and call their
    build_dependencies methods.
    """
    for module in self.modules:
        module.build_dependencies()
    for package in self.packages:
        package.build_dependencies()

build_tree ¤

build_tree() -> None

To be overridden.

Source code in src/dependenpy/_internal/node.py
154
155
156
def build_tree(self) -> None:
    """To be overridden."""
    raise NotImplementedError

get ¤

get(item: str) -> Package | Module

Get item through __getitem__ and cache the result.

Parameters:

  • item ¤

    (str) –

    Name of package or module.

Returns:

Source code in src/dependenpy/_internal/node.py
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
def get(self, item: str) -> Package | Module:
    """Get item through `__getitem__` and cache the result.

    Parameters:
        item: Name of package or module.

    Returns:
        The corresponding object.
    """
    if item not in self._item_cache:
        try:
            obj = self.__getitem__(item)
        except KeyError:
            obj = None
        self._item_cache[item] = obj
    return self._item_cache[item]

get_target ¤

get_target(target: str) -> Package | Module

Get the result of _get_target, cache it and return it.

Parameters:

  • target ¤

    (str) –

    Target to find.

Returns:

  • Package | Module –

    Package containing target or corresponding module.

Source code in src/dependenpy/_internal/node.py
191
192
193
194
195
196
197
198
199
200
201
202
def get_target(self, target: str) -> Package | Module:
    """Get the result of _get_target, cache it and return it.

    Parameters:
        target: Target to find.

    Returns:
        Package containing target or corresponding module.
    """
    if target not in self._target_cache:
        self._target_cache[target] = self._get_target(target)
    return self._target_cache[target]

print_graph ¤

print_graph(
    format: str | None = None,
    output: IO = stdout,
    depth: int = 0,
    **kwargs: Any,
) -> None

Print the graph for self's nodes.

Parameters:

  • format ¤

    (str | None, default: None ) –

    Output format (csv, json or text).

  • output ¤

    (IO, default: stdout ) –

    File descriptor on which to write.

  • depth ¤

    (int, default: 0 ) –

    Depth of the graph.

  • **kwargs ¤

    (Any, default: {} ) –

    Additional keyword arguments passed to graph.print.

Source code in src/dependenpy/_internal/node.py
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
def print_graph(
    self,
    format: str | None = None,  # noqa: A002
    output: IO = sys.stdout,
    depth: int = 0,
    **kwargs: Any,
) -> None:
    """Print the graph for self's nodes.

    Parameters:
        format: Output format (csv, json or text).
        output: File descriptor on which to write.
        depth: Depth of the graph.
        **kwargs: Additional keyword arguments passed to `graph.print`.
    """
    graph = self.as_graph(depth=depth)
    graph.print(format=format, output=output, **kwargs)

print_matrix ¤

print_matrix(
    format: str | None = None,
    output: IO = stdout,
    depth: int = 0,
    **kwargs: Any,
) -> None

Print the matrix for self's nodes.

Parameters:

  • format ¤

    (str | None, default: None ) –

    Output format (csv, json or text).

  • output ¤

    (IO, default: stdout ) –

    File descriptor on which to write.

  • depth ¤

    (int, default: 0 ) –

    Depth of the matrix.

  • **kwargs ¤

    (Any, default: {} ) –

    Additional keyword arguments passed to matrix.print.

Source code in src/dependenpy/_internal/node.py
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
def print_matrix(
    self,
    format: str | None = None,  # noqa: A002
    output: IO = sys.stdout,
    depth: int = 0,
    **kwargs: Any,
) -> None:
    """Print the matrix for self's nodes.

    Parameters:
        format: Output format (csv, json or text).
        output: File descriptor on which to write.
        depth: Depth of the matrix.
        **kwargs: Additional keyword arguments passed to `matrix.print`.
    """
    matrix = self.as_matrix(depth=depth)
    matrix.print(format=format, output=output, **kwargs)

print_treemap ¤

print_treemap(
    format: str | None = None,
    output: IO = stdout,
    **kwargs: Any,
) -> None

Print the matrix for self's nodes.

Parameters:

  • format ¤

    (str | None, default: None ) –

    Output format (csv, json or text).

  • output ¤

    (IO, default: stdout ) –

    File descriptor on which to write.

  • **kwargs ¤

    (Any, default: {} ) –

    Additional keyword arguments passed to treemap.print.

Source code in src/dependenpy/_internal/node.py
282
283
284
285
286
287
288
289
290
291
def print_treemap(self, format: str | None = None, output: IO = sys.stdout, **kwargs: Any) -> None:  # noqa: A002
    """Print the matrix for self's nodes.

    Parameters:
        format: Output format (csv, json or text).
        output: File descriptor on which to write.
        **kwargs: Additional keyword arguments passed to `treemap.print`.
    """
    treemap = self.as_treemap()
    treemap.print(format=format, output=output, **kwargs)

TreeMap ¤

TreeMap(*nodes: Any, value: int = -1)

Bases: PrintMixin

TreeMap class.

Parameters:

  • *nodes ¤

    (Any, default: () ) –

    the nodes from which to build the treemap.

  • value ¤

    (int, default: -1 ) –

    the value of the current area.

Methods:

  • print –

    Print the object in a file or on standard output by default.

Attributes:

  • value –

    The value of the current area.

Source code in src/dependenpy/_internal/structures.py
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
def __init__(self, *nodes: Any, value: int = -1):  # noqa: ARG002
    """Initialization method.

    Arguments:
        *nodes: the nodes from which to build the treemap.
        value: the value of the current area.
    """
    # if nodes:
    #     matrix_lower_level = Matrix(*nodes, depth=2)
    #     matrix_current_level = Matrix(*nodes, depth=1)
    #     if value == -1:
    #         value = sum(c for row in matrix_current_level.data for c in row)
    #     splits = [0]
    #     key_comp = matrix_lower_level.keys[0].split('.')[0]
    #     i = 1
    #     for key in matrix_lower_level.keys[1:]:
    #         key = key.split('.')[0]
    #         if key != key_comp:
    #             splits.append(i)
    #             key_comp = key
    #         i += 1
    #     splits.append(i)
    #
    #     self.data = []
    #     for i in range(len(splits) - 1):
    #         self.data.append([])
    #         rows = matrix_lower_level.data[splits[i]:splits[i+1]]
    #         for j in range(len(splits) - 1):
    #             self.data[i].append([row[splits[j]:splits[j+1]] for row in rows])

    self.value = value
    """The value of the current area."""

value instance-attribute ¤

value = value

The value of the current area.

print ¤

print(
    format: str | None = TEXT,
    output: IO = stdout,
    **kwargs: Any,
) -> None

Print the object in a file or on standard output by default.

Parameters:

  • format ¤

    (str | None, default: TEXT ) –

    Output format (csv, json or text).

  • output ¤

    (IO, default: stdout ) –

    Descriptor to an opened file (default to standard output).

  • **kwargs ¤

    (Any, default: {} ) –

    Additional arguments.

Source code in src/dependenpy/_internal/helpers.py
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
def print(self, format: str | None = TEXT, output: IO = sys.stdout, **kwargs: Any) -> None:  # noqa: A002
    """Print the object in a file or on standard output by default.

    Parameters:
        format: Output format (csv, json or text).
        output: Descriptor to an opened file (default to standard output).
        **kwargs: Additional arguments.
    """
    if format is None:
        format = TEXT

    if format != TEXT:
        kwargs.pop("zero", "")

    if format == TEXT:
        print(self._to_text(**kwargs), file=output)
    elif format == CSV:
        print(self._to_csv(**kwargs), file=output)
    elif format == JSON:
        print(self._to_json(**kwargs), file=output)

Vertex ¤

Vertex(name: str)

Vertex class. Used in Graph class.

Parameters:

  • name ¤

    (str) –

    name of the vertex.

Methods:

Attributes:

Source code in src/dependenpy/_internal/structures.py
221
222
223
224
225
226
227
228
229
230
231
232
def __init__(self, name: str) -> None:
    """Initialization method.

    Parameters:
        name (str): name of the vertex.
    """
    self.name = name
    """Name of the vertex."""
    self.edges_in: set[Edge] = set()
    """Incoming edges."""
    self.edges_out: set[Edge] = set()
    """Outgoing edges."""

edges_in instance-attribute ¤

edges_in: set[Edge] = set()

Incoming edges.

edges_out instance-attribute ¤

edges_out: set[Edge] = set()

Outgoing edges.

name instance-attribute ¤

name = name

Name of the vertex.

connect_from ¤

connect_from(vertex: Vertex, weight: int = 1) -> Edge

Connect another vertex to this one.

Parameters:

  • vertex ¤

    (Vertex) –

    Vertex to connect from.

  • weight ¤

    (int, default: 1 ) –

    Weight of the edge.

Returns:

  • Edge –

    The newly created edge.

Source code in src/dependenpy/_internal/structures.py
252
253
254
255
256
257
258
259
260
261
262
263
264
265
def connect_from(self, vertex: Vertex, weight: int = 1) -> Edge:
    """Connect another vertex to this one.

    Parameters:
        vertex: Vertex to connect from.
        weight: Weight of the edge.

    Returns:
        The newly created edge.
    """
    for edge in self.edges_in:
        if vertex == edge.vertex_out:
            return edge
    return Edge(vertex, self, weight)

connect_to ¤

connect_to(vertex: Vertex, weight: int = 1) -> Edge

Connect this vertex to another one.

Parameters:

  • vertex ¤

    (Vertex) –

    Vertex to connect to.

  • weight ¤

    (int, default: 1 ) –

    Weight of the edge.

Returns:

  • Edge –

    The newly created edge.

Source code in src/dependenpy/_internal/structures.py
237
238
239
240
241
242
243
244
245
246
247
248
249
250
def connect_to(self, vertex: Vertex, weight: int = 1) -> Edge:
    """Connect this vertex to another one.

    Parameters:
        vertex: Vertex to connect to.
        weight: Weight of the edge.

    Returns:
        The newly created edge.
    """
    for edge in self.edges_out:
        if vertex == edge.vertex_in:
            return edge
    return Edge(self, vertex, weight)

get_parser ¤

get_parser() -> ArgumentParser

Return the CLI argument parser.

Returns:

Source code in src/dependenpy/_internal/cli.py
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
def get_parser() -> argparse.ArgumentParser:
    """Return the CLI argument parser.

    Returns:
        An argparse parser.
    """
    parser = argparse.ArgumentParser(
        prog="dependenpy",
        add_help=False,
        description="Command line tool for dependenpy Python package.",
    )
    mxg = parser.add_mutually_exclusive_group(required=False)

    parser.add_argument(
        "packages",
        metavar="PACKAGES",
        nargs=argparse.ONE_OR_MORE,
        help="The package list. Can be a comma-separated list. Each package "
        "must be either a valid path or a package in PYTHONPATH.",
    )
    parser.add_argument(
        "-d",
        "--depth",
        default=None,
        type=int,
        dest="depth",
        help="Specify matrix or graph depth. Default: best guess.",
    )
    parser.add_argument(
        "-f",
        "--format",
        choices=FORMAT,
        default="text",
        dest="format",
        help="Output format. Default: text.",
    )
    mxg.add_argument(
        "-g",
        "--show-graph",
        action="store_true",
        dest="graph",
        default=False,
        help="Show the graph (no text format). Default: false.",
    )
    parser.add_argument(
        "-G",
        "--greedy",
        action="store_true",
        dest="greedy",
        default=False,
        help="Explore subdirectories even if they do not contain an "
        "__init__.py file. Can make execution slower. Default: false.",
    )
    parser.add_argument(
        "-h",
        "--help",
        action="help",
        default=argparse.SUPPRESS,
        help="Show this help message and exit.",
    )
    parser.add_argument(
        "-i",
        "--indent",
        default=None,
        type=int,
        dest="indent",
        help="Specify output indentation. CSV will never be indented. "
        "Text will always have new-lines. JSON can be minified with "
        "a negative value. Default: best guess.",
    )
    mxg.add_argument(
        "-l",
        "--show-dependencies-list",
        action="store_true",
        dest="dependencies",
        default=False,
        help="Show the dependencies list. Default: false.",
    )
    mxg.add_argument(
        "-m",
        "--show-matrix",
        action="store_true",
        dest="matrix",
        default=False,
        help="Show the matrix. Default: true unless -g, -l or -t.",
    )
    parser.add_argument(
        "-o",
        "--output",
        action="store",
        dest="output",
        default=sys.stdout,
        help="Output to given file. Default: stdout.",
    )
    mxg.add_argument(
        "-t",
        "--show-treemap",
        action="store_true",
        dest="treemap",
        default=False,
        help="Show the treemap (work in progress). Default: false.",
    )
    parser.add_argument(
        "-v",
        "--version",
        action="version",
        version=f"dependenpy {debug._get_version()}",
        help="Show the current version of the program and exit.",
    )
    parser.add_argument(
        "-z",
        "--zero",
        dest="zero",
        default="0",
        help="Character to use for cells with value=0 (text matrix display only).",
    )

    parser.add_argument("--debug-info", action=_DebugInfo, help="Print debug information.")
    return parser

guess_depth ¤

guess_depth(packages: Sequence[str]) -> int

Guess the optimal depth to use for the given list of arguments.

Parameters:

Returns:

  • int –

    Guessed depth to use.

Source code in src/dependenpy/_internal/helpers.py
72
73
74
75
76
77
78
79
80
81
82
83
def guess_depth(packages: Sequence[str]) -> int:
    """Guess the optimal depth to use for the given list of arguments.

    Parameters:
        packages: List of packages.

    Returns:
        Guessed depth to use.
    """
    if len(packages) == 1:
        return packages[0].count(".") + 2
    return min(package.count(".") for package in packages) + 1

main ¤

main(args: list[str] | None = None) -> int

Run the main program.

This function is executed when you type dependenpy or python -m dependenpy.

Parameters:

  • args ¤

    (list[str] | None, default: None ) –

    Arguments passed from the command line.

Returns:

  • int –

    An exit code. 0 (OK), 1 (dsm empty) or 2 (error).

Source code in src/dependenpy/_internal/cli.py
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
def main(args: list[str] | None = None) -> int:
    """Run the main program.

    This function is executed when you type `dependenpy` or `python -m dependenpy`.

    Parameters:
        args: Arguments passed from the command line.

    Returns:
        An exit code. 0 (OK), 1 (dsm empty) or 2 (error).
    """
    parser = get_parser()
    opts = parser.parse_args(args=args)
    if not (opts.matrix or opts.dependencies or opts.treemap or opts.graph):
        opts.matrix = True

    dsm = DSM(*_get_packages(opts), build_tree=True, build_dependencies=True, enforce_init=not opts.greedy)
    if dsm.empty:
        return 1

    # init colorama
    init()

    try:
        _run(opts, dsm)
    except BrokenPipeError:
        # avoid traceback
        return 2

    return 0