Skip to content

Commit 935cf82

Browse files
committed
Update documentation related to Python environments
Update README.md to reflect that we're now using the _current_ Python environment (i.e. 'sys.path') only as an ultimate fallback when (a) `--pyenv` is not used, and (b) we're unable to find Python environments under 'basepath'. Update the related FAQs accordingly. Also update the --help text to reflect that `basepath` now also affect Python environment calculation.
1 parent 2da0445 commit 935cf82

File tree

2 files changed

+74
-56
lines changed

2 files changed

+74
-56
lines changed

README.md

+64-47
Original file line numberDiff line numberDiff line change
@@ -138,22 +138,18 @@ When FawltyDeps looks for undeclared and unused dependencies, it needs to match
138138
`import` statements in your code with corresponding package dependencies
139139
declared in your project configuration.
140140

141-
To solve this, FawltyDeps adopts several strategies: mapping provided by the user,
142-
identity mapping, and most powerful of all - using your python environment.
141+
To solve this, FawltyDeps uses a sequence of resolvers (aka. mapping strategies)
142+
to determine which Python packages that provide which import names:
143143

144144
#### Python environment mapping
145145

146-
FawltyDeps looks at the packages installed in your _current
147-
Python environment_ and what import names each of them provide in order to
148-
correctly match your dependencies against your imports.
146+
First of all FawltyDeps looks for _Python environments_ (virtualenvs or similar
147+
directories like `.venv` or `__pypackages__`.) inside your project (i.e. under
148+
`basepath`, if given, or the current directory).
149149

150-
The _current Python environment_ in this case is the environment in which
151-
FawltyDeps itself is installed. This works well when you, for example,
152-
`pip install fawltydeps` into the same virtualenv as your project dependencies.
153-
154-
If you instead want FawltyDeps to look into a _different_ Python environment for
155-
mapping dependencies to import names, you can use the `--pyenv` option,
156-
for example:
150+
You can use the `--pyenv` option (or the `pyenvs` configuration directive)
151+
to point FawltyDeps at a specific Python environment located within your project
152+
or elsewhere. For example:
157153

158154
```sh
159155
fawltydeps --code my_package/ --deps pyproject.toml --pyenv .venv/
@@ -166,17 +162,23 @@ This will tell FawltyDeps:
166162
- to use the Python environment at `.venv/` to map dependency names in
167163
`pyproject.toml` into import names used in your code under `my_package/`
168164

165+
If `--pyenv` is not used, and no Python environments are found within your project,
166+
FawltyDeps will fall back to looking at your _current Python environment_:
167+
This is the environment in which FawltyDeps itself is installed.
168+
This works well when you, for example, `pip install fawltydeps` into the same
169+
virtualenv as your project dependencies.
170+
169171
You can use `--pyenv` multiple times to have FawltyDeps look for packages in
170-
multiple Python environments. When mapping a dependency into import names,
171-
FawltyDeps will then use the union of all imports provided by all matching
172-
packages across those Python environments as valid import names for that
173-
dependency.
172+
multiple Python environments. In this case (or when multiple Python environments
173+
are found inside your project) FawltyDeps will use the union (superset) of all
174+
imports provided by all matching packages across those Python environments as
175+
valid import names for that dependency.
174176

175177
#### Identity mapping
176178

177-
When FawltyDeps is unable to find an installed package that corresponds to a
178-
declared dependency, FawltyDeps will fall back to an "identity mapping", where
179-
it _assumes_ that the dependency provides a single import of the same name,
179+
When unable to find an installed package that corresponds to a declared
180+
dependency, FawltyDeps will fall back to an "identity mapping", where it
181+
_assumes_ that the dependency provides a single import of the same name,
180182
i.e. it will expect that when you depend on `some_package`, then that should
181183
correspond to `import some_package` statements in your code.
182184

@@ -188,8 +190,8 @@ project dependencies](#why-must-fawltydeps-run-in-the-same-python-environment-as
188190

189191
#### User-defined mapping
190192

191-
You may define your mapping by providing a toml file with package to imports mapping,
192-
`my_mapping.toml`:
193+
As a final solution and/or an ultimate override, you may define your own mapping
194+
of dependency names to import names, by providing a TOML file like this:
193195

194196
```toml
195197
my-package = ["mpkg"]
@@ -203,9 +205,11 @@ To use your mapping, run:
203205
fawltydeps --custom-mapping-file my_mapping.toml
204206
```
205207

206-
FawltyDeps will parse `my_mapping.toml` file and use extracted mapping for matching dependencies to imports.
208+
FawltyDeps will parse your `my_mapping.toml` file and use the extracted mapping
209+
for matching dependencies to imports.
207210

208-
You may also place the custom mapping in the `pyproject.toml` file of your project, inside a `[tool.fawltydeps.custom_mapping]` section, like this:
211+
You may also place the custom mapping in the `pyproject.toml` file of your
212+
project, inside a `[tool.fawltydeps.custom_mapping]` section, like this:
209213

210214
```toml
211215
[tool.fawltydeps.custom_mapping]
@@ -214,9 +218,10 @@ scikit-learn = ["sklearn"]
214218
multiple-modules = ["module1", "module2"]
215219
```
216220

217-
Caution when using your mapping is advised. The user-defined mapping takes precedence over all other resolving strategies.
218-
If the mapping file has some stale mapping entries, they will not be resolved by
219-
Python environment resolver (which in general is the most accurate).
221+
Caution when using your mapping is advised: The user-defined mapping takes
222+
precedence over the other resolvers documented above. For example, if the
223+
mapping file has some stale/incorrect mapping entries, they will _not_ be
224+
resolved by the Python environment resolver (which is geenrally more accurate).
220225

221226
### Ignoring irrelevant results
222227

@@ -276,10 +281,11 @@ Here is a complete list of configuration directives we support:
276281
Defaults to the current directory, i.e. like `code = ["."]`.
277282
- `deps`: Files or directories containing the declared dependencies.
278283
Defaults to the current directory, i.e. like `deps = ["."]`.
279-
- `pyenvs`: Python environments (directories like `.venv`, `__pypackages__`, or
280-
similar) to use for resolving project dependencies into provided import names.
281-
Defaults to an empty list, i.e. like `pyenvs = []`, which is interpreted as
282-
using the Python environment where FawltyDeps is installed (aka. `sys.path`).
284+
- `pyenvs`: Where to look for Python environments (directories like `.venv`,
285+
`__pypackages__`, or similar) to be uses for resolving project dependencies
286+
into provided import names. Defaults to looking for Python environments under
287+
the current directory, i.e. like `pyenvs = ["."]`. If none are found, use the
288+
Python environment where FawltyDeps is installed (aka. `sys.path`).
283289
- `output_format`: Which output format to use by default. One of `human_summary`,
284290
`human_detailed`, or `json`.
285291
The default corresponds to `output_format = "human_summary"`.
@@ -507,13 +513,19 @@ fawltydeps libX
507513

508514
### Why must FawltyDeps run in the same Python environment as my project dependencies?
509515

510-
As explained above in the section on [resolving dependencies via your Python
511-
environment](#resolving-dependencies-via-your-python-environment), the core
512-
logic of FawltyDeps needs to match `import` statements in your code with
513-
dependencies declared in your project configuration. This is straightforward
514-
for many packages: for example you `pip install requests` and then
515-
you can `import requests` in your code. However, this mapping from the name you
516-
install to the name you `import` is not always self-evident:
516+
(This is no longer true since FawltyDeps v0.11: FawltyDeps should be able to
517+
automatically find your project dependencies when they are installed in a Python
518+
environment that exists within your project. If your project dependencies are
519+
installed elsewhere, you can point FawltyDeps in their direction with `--pyenv`,
520+
as explained above in the section on
521+
[Python environment mapping](#python-environment-mapping))
522+
523+
The reason why FawltyDeps need to find your project dependencies _somewhere_ is
524+
that the core logic of FawltyDeps needs to match `import` statements in your
525+
code with dependencies declared in your project configuration. This seems
526+
straightforward for many packages: for example you `pip install requests` and
527+
then you can `import requests` in your code. However, this mapping from the name
528+
you install to the name you `import` is not always self-evident:
517529

518530
- There are sometimes differences between the package name that you
519531
declare as a dependency, and the `import` name it provides. For example, you
@@ -524,11 +536,18 @@ install to the name you `import` is not always self-evident:
524536
FawltyDeps need to figure out that this corresponds to the `setuptools`
525537
dependency.
526538

527-
To solve this, FawltyDeps looks at the packages installed in your current Python
528-
environment (or the environment given by the `--pyenv` option) to correctly map
529-
dependencies (package names) into the imports that they provide.
539+
To solve this, FawltyDeps looks at the packages installed in your Python
540+
environment to correctly map dependencies (package names) into the imports that
541+
they provide. This is:
542+
543+
- any Python environment found via the `--pyenv` option, or
544+
- any Python environment found within your project (`basepath` or the current
545+
directory).
546+
- Failing that, FawltyDeps will use the _current Python environment_,
547+
i.e. the one in which FawltyDeps itself is running.
530548

531-
However, when an installed package is not found for a declared dependency, the
549+
As a final resort, when an installed package is not found for a declared
550+
dependency, the
532551
_identity mapping_ that FawltyDeps falls back to will still do a good job for
533552
the majority of dependencies where the import name is indeed identical to the
534553
package name that you depend on.
@@ -545,13 +564,11 @@ _undeclared_ and `scikit-learn` as an _unused_ dependency.
545564

546565
This is very much related to the above question. `scikit-learn` is an example
547566
of a package that exposes a different import name: `sklearn`.
548-
When `scikit-learn` is not installed in the current Python environment (the one
549-
that FawltyDeps uses to find these mappings), then FawltyDeps is unable to make
550-
the connection between these two names.
567+
When `scikit-learn` is not found in the Python environment(s) used by FawltyDeps,
568+
then FawltyDeps is unable to make the connection between these two names.
551569

552-
To solve this problem, make sure that you either install and run FawltyDeps
553-
in a development environment (e.g. virtualenv) where your project's dependencies
554-
(including `scikit-learn`) are also installed. Alternatively, you can use the
570+
To solve this problem, make sure that `scikit-learn` is installed in a Python
571+
environment that belongs to your project. Alternatively, you can use the
555572
`--pyenv` option to point at a Python environment where `scikit-learn` and your
556573
other dependencies are installed.
557574

fawltydeps/cli_parser.py

+10-9
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,7 @@ def populate_output_formats(parser: argparse._ActionsContainer) -> None:
107107

108108

109109
def populate_parser_paths_options(parser: argparse._ActionsContainer) -> None:
110-
"""Add the source paths (code, deps, env) Settings members to the parser.
110+
"""Add the source paths (code, deps, pyenv) Settings members to the parser.
111111
112112
None of these options should specify default values
113113
(and the parser-wide default value should be argparse.SUPPRESS).
@@ -120,8 +120,8 @@ def populate_parser_paths_options(parser: argparse._ActionsContainer) -> None:
120120
"basepaths",
121121
type=lambda p: None if p == argparse.SUPPRESS else Path(p),
122122
nargs="*",
123-
help="(Optional) directory in which to search for code (imports) "
124-
"and/or dependency declarations",
123+
help="(Optional) directory in which to search for code (imports),"
124+
" dependency declarations and/or Python environments",
125125
)
126126
parser.add_argument(
127127
"--code",
@@ -130,8 +130,8 @@ def populate_parser_paths_options(parser: argparse._ActionsContainer) -> None:
130130
type=parse_path_or_stdin,
131131
metavar="PATH_OR_STDIN",
132132
help=(
133-
"Code to parse for import statements (file or directory, use '-' "
134-
"to read code from stdin; defaults to the current directory)"
133+
"Code to parse for import statements (file or directory, use '-'"
134+
" to read code from stdin; defaults to the current directory)"
135135
),
136136
)
137137
parser.add_argument(
@@ -150,8 +150,8 @@ def populate_parser_paths_options(parser: argparse._ActionsContainer) -> None:
150150
type=read_parser_choice,
151151
choices=list(ParserChoice),
152152
help=(
153-
"Name of the parsing strategy to use for dependency declarations, "
154-
"useful for when the file to parse doesn't match a standard name"
153+
"Name of the parsing strategy to use for dependency declarations,"
154+
" useful for when the file to parse doesn't match a standard name"
155155
),
156156
)
157157
parser.add_argument(
@@ -163,8 +163,9 @@ def populate_parser_paths_options(parser: argparse._ActionsContainer) -> None:
163163
metavar="PYENV_DIR",
164164
help=(
165165
"Where to find Python environments that have project dependencies"
166-
" installed. When empty (the default), fall back to the Python"
167-
" environment where FawltyDeps is installed."
166+
" installed. Defaults to looking for Python environments under the"
167+
" current directory, or failing that, using the Python environment"
168+
" where FawltyDeps is installed."
168169
),
169170
)
170171
parser.add_argument(

0 commit comments

Comments
 (0)