Skip to content

Commit 6688240

Browse files
committed
Add docs for better namespace support
1 parent 99a7a7f commit 6688240

3 files changed

Lines changed: 30 additions & 12 deletions

File tree

README.rst

Lines changed: 24 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -114,20 +114,37 @@ You may analyse multiple root packages. To do this, pass each package name as a
114114
Namespace packages
115115
------------------
116116

117-
Graphs can also be built from `portions`_ of `namespace packages`_. To do this, provide the portion name, rather than the namespace name::
118-
119-
>>> graph = grimp.build_graph('somenamespace.foo')
117+
Graphs can be built either from `namespace packages`_ or from their `portions`_.
120118

121119
What's a namespace package?
122120
###########################
123121

124-
Namespace packages are a Python feature allows subpackages to be distributed independently, while still importable under a shared namespace. This is, for example, used by `the Python client for Google's Cloud Logging API`_. When installed, it is importable in Python as ``google.cloud.logging``. The parent packages ``google`` and ``google.cloud`` are both namespace packages, while ``google.cloud.logging`` is known as the 'portion'. Other portions in the same namespace can be installed separately, for example ``google.cloud.secretmanager``.
122+
Namespace packages are a Python feature allows subpackages to be distributed independently, while
123+
still importable under a shared namespace.
124+
125+
This is used by
126+
`the Python client for Google's Cloud Logging API`_, for example. When installed, it is importable
127+
in Python as ``google.cloud.logging``. The parent packages ``google`` and ``google.cloud`` are both namespace
128+
packages, while ``google.cloud.logging`` is known as the 'portion'. Other portions in the same
129+
namespace can be installed separately, for example ``google.cloud.secretmanager``.
130+
131+
Examples::
132+
133+
# In this one, the portion is supplied. Neither "google" nor "google.cloud"
134+
# will appear in the graph.
135+
>>> graph = grimp.build_graph("google.cloud.logging")
136+
137+
# In this one, a namespace is supplied.
138+
# Neither "google" nor "google.cloud" will appear in the graph,
139+
# as will other installed packages under the "google" namespace such
140+
# as "google.auth".
141+
>>> graph = grimp.build_graph("google")
125142

126-
Grimp expects the package name passed to ``build_graph`` to be a portion, rather than a namespace package. So in the case of the example above, the graph should be built like so::
143+
# This one supplies a subnamespace of "google" - it will include
144+
# "google.cloud.logging" and "google.cloud.secretmanager" but not "google.auth".
145+
>>> graph = grimp.build_graph("google.cloud")
127146

128-
>>> graph = grimp.build_graph('google.cloud.logging')
129147

130-
If, instead, a namespace package is passed (e.g. ``grimp.build_graph('google.cloud')``), Grimp will raise ``NamespacePackageEncountered``.
131148

132149
.. _portions: https://docs.python.org/3/glossary.html#term-portion
133150
.. _namespace packages: https://docs.python.org/3/glossary.html#term-namespace-package

docs/usage.rst

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -57,19 +57,20 @@ Building the graph
5757
Build and return an ImportGraph for the supplied package or packages.
5858

5959
:param str package_name: The name of an importable package, for example ``'mypackage'``. For regular packages, this
60-
must be the top level package (i.e. one with no dots in its name). However, in the special case of
61-
`namespace packages`_, the name of the *portion* should be supplied, for example ``'mynamespace.foo'``.
60+
must be the top level package (i.e. one with no dots in its name). In the special case of
61+
`namespace packages`_, the name of the *portion* may be supplied instead, for example ``'mynamespace.foo'``.
62+
If the portion is supplied, its ancestor packages will not be included in the graph.
6263
:param tuple[str, ...] additional_package_names: Tuple of any additional package names. These can be
6364
supplied as positional arguments, as in the example above.
6465
:param bool, optional include_external_packages: Whether to include external packages in the import graph. If this is ``True``,
6566
any other top level packages (including packages in the standard library) that are imported by this package will
6667
be included in the graph as squashed modules (see `Terminology`_ above).
6768

68-
The behaviour is more complex if one of the internal packages is a `namespace portion`_.
69+
The behaviour is more complex if one of the specified packages is a `namespace portion`_.
6970
In this case, the squashed module will have the shallowest name that doesn't clash with any internal modules.
7071
For example, in a graph with internal packages ``namespace.foo`` and ``namespace.bar.one.green``,
7172
``namespace.bar.one.orange.alpha`` would be added to the graph as ``namespace.bar.one.orange``. However, in a graph
72-
with only ``namespace.foo`` as an internal package, the same external module would be added as
73+
with only ``namespace.foo`` passed, the same external module would be added as
7374
``namespace.bar``.
7475

7576
*Note: external packages are only analysed as modules that are imported; any imports they make themselves will

src/grimp/application/usecases.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ def build_graph(
3232
3333
Args:
3434
- package_name: the name of the top level package for which to build the graph.
35-
- additional_package_names: tuple of the
35+
- additional_package_names: tuple of additional packages to build the graph from.
3636
- include_external_packages: whether to include any external packages in the graph.
3737
- exclude_type_checking_imports: whether to exclude imports made in type checking guards.
3838
- cache_dir: The directory to use for caching the graph.

0 commit comments

Comments
 (0)