pyflyby 1.10.0__tar.gz → 1.10.2__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of pyflyby might be problematic. Click here for more details.
- {pyflyby-1.10.0 → pyflyby-1.10.2}/.github/workflows/docs.yml +1 -1
- {pyflyby-1.10.0 → pyflyby-1.10.2}/.github/workflows/lint.yml +1 -2
- {pyflyby-1.10.0 → pyflyby-1.10.2}/.github/workflows/test.yml +1 -1
- {pyflyby-1.10.0 → pyflyby-1.10.2}/PKG-INFO +27 -9
- {pyflyby-1.10.0 → pyflyby-1.10.2}/README.rst +22 -5
- {pyflyby-1.10.0 → pyflyby-1.10.2}/bin/tidy-imports +8 -1
- {pyflyby-1.10.0 → pyflyby-1.10.2}/doc/conf.py +1 -1
- {pyflyby-1.10.0 → pyflyby-1.10.2}/lib/python/pyflyby/_cmdline.py +62 -19
- {pyflyby-1.10.0 → pyflyby-1.10.2}/lib/python/pyflyby/_interactive.py +2 -2
- {pyflyby-1.10.0 → pyflyby-1.10.2}/lib/python/pyflyby/_modules.py +10 -4
- {pyflyby-1.10.0 → pyflyby-1.10.2}/lib/python/pyflyby/_version.py +1 -1
- {pyflyby-1.10.0 → pyflyby-1.10.2}/meson.build +1 -1
- {pyflyby-1.10.0 → pyflyby-1.10.2}/pyproject.toml +4 -3
- {pyflyby-1.10.0 → pyflyby-1.10.2}/src/_fast_iter_modules.cpp +26 -15
- {pyflyby-1.10.0 → pyflyby-1.10.2}/tests/test_cmdline.py +261 -1
- {pyflyby-1.10.0 → pyflyby-1.10.2}/tests/test_modules.py +26 -9
- {pyflyby-1.10.0 → pyflyby-1.10.2}/.github/dependabot.yml +0 -0
- {pyflyby-1.10.0 → pyflyby-1.10.2}/.gitignore +0 -0
- {pyflyby-1.10.0 → pyflyby-1.10.2}/.pyflyby +0 -0
- {pyflyby-1.10.0 → pyflyby-1.10.2}/CONTRIBUTING.md +0 -0
- {pyflyby-1.10.0 → pyflyby-1.10.2}/LICENSE.txt +0 -0
- {pyflyby-1.10.0 → pyflyby-1.10.2}/MANIFEST.in +0 -0
- {pyflyby-1.10.0 → pyflyby-1.10.2}/bin/autoipython +0 -0
- {pyflyby-1.10.0 → pyflyby-1.10.2}/bin/autopython +0 -0
- {pyflyby-1.10.0 → pyflyby-1.10.2}/bin/collect-exports +0 -0
- {pyflyby-1.10.0 → pyflyby-1.10.2}/bin/collect-imports +0 -0
- {pyflyby-1.10.0 → pyflyby-1.10.2}/bin/create-imports +0 -0
- {pyflyby-1.10.0 → pyflyby-1.10.2}/bin/find-import +0 -0
- {pyflyby-1.10.0 → pyflyby-1.10.2}/bin/list-bad-xrefs +0 -0
- {pyflyby-1.10.0 → pyflyby-1.10.2}/bin/prune-broken-imports +0 -0
- {pyflyby-1.10.0 → pyflyby-1.10.2}/bin/py +0 -0
- {pyflyby-1.10.0 → pyflyby-1.10.2}/bin/pyflyby-diff +0 -0
- {pyflyby-1.10.0 → pyflyby-1.10.2}/bin/reformat-imports +0 -0
- {pyflyby-1.10.0 → pyflyby-1.10.2}/bin/replace-star-imports +0 -0
- {pyflyby-1.10.0 → pyflyby-1.10.2}/bin/saveframe +0 -0
- {pyflyby-1.10.0 → pyflyby-1.10.2}/bin/transform-imports +0 -0
- {pyflyby-1.10.0 → pyflyby-1.10.2}/codecov.yml +0 -0
- {pyflyby-1.10.0 → pyflyby-1.10.2}/conftest.py +0 -0
- {pyflyby-1.10.0 → pyflyby-1.10.2}/doc/LICENSE.txt +0 -0
- {pyflyby-1.10.0 → pyflyby-1.10.2}/doc/Makefile +0 -0
- {pyflyby-1.10.0 → pyflyby-1.10.2}/doc/TODO.txt +0 -0
- {pyflyby-1.10.0 → pyflyby-1.10.2}/doc/__init__.py +0 -0
- {pyflyby-1.10.0 → pyflyby-1.10.2}/doc/api/api.rst +0 -0
- {pyflyby-1.10.0 → pyflyby-1.10.2}/doc/api/autoimp.rst +0 -0
- {pyflyby-1.10.0 → pyflyby-1.10.2}/doc/api/cmdline.rst +0 -0
- {pyflyby-1.10.0 → pyflyby-1.10.2}/doc/api/comms.rst +0 -0
- {pyflyby-1.10.0 → pyflyby-1.10.2}/doc/api/dbg.rst +0 -0
- {pyflyby-1.10.0 → pyflyby-1.10.2}/doc/api/file.rst +0 -0
- {pyflyby-1.10.0 → pyflyby-1.10.2}/doc/api/flags.rst +0 -0
- {pyflyby-1.10.0 → pyflyby-1.10.2}/doc/api/format.rst +0 -0
- {pyflyby-1.10.0 → pyflyby-1.10.2}/doc/api/idents.rst +0 -0
- {pyflyby-1.10.0 → pyflyby-1.10.2}/doc/api/importclns.rst +0 -0
- {pyflyby-1.10.0 → pyflyby-1.10.2}/doc/api/importdb.rst +0 -0
- {pyflyby-1.10.0 → pyflyby-1.10.2}/doc/api/imports2s.rst +0 -0
- {pyflyby-1.10.0 → pyflyby-1.10.2}/doc/api/importstmt.rst +0 -0
- {pyflyby-1.10.0 → pyflyby-1.10.2}/doc/api/interactive.rst +0 -0
- {pyflyby-1.10.0 → pyflyby-1.10.2}/doc/api/livepatch.rst +0 -0
- {pyflyby-1.10.0 → pyflyby-1.10.2}/doc/api/log.rst +0 -0
- {pyflyby-1.10.0 → pyflyby-1.10.2}/doc/api/modules.rst +0 -0
- {pyflyby-1.10.0 → pyflyby-1.10.2}/doc/api/parse.rst +0 -0
- {pyflyby-1.10.0 → pyflyby-1.10.2}/doc/api/py.rst +0 -0
- {pyflyby-1.10.0 → pyflyby-1.10.2}/doc/api/util.rst +0 -0
- {pyflyby-1.10.0 → pyflyby-1.10.2}/doc/cli/autoipython.rst +0 -0
- {pyflyby-1.10.0 → pyflyby-1.10.2}/doc/cli/cli.rst +0 -0
- {pyflyby-1.10.0 → pyflyby-1.10.2}/doc/cli/collect_exports.rst +0 -0
- {pyflyby-1.10.0 → pyflyby-1.10.2}/doc/cli/collect_imports.rst +0 -0
- {pyflyby-1.10.0 → pyflyby-1.10.2}/doc/cli/find_import.rst +0 -0
- {pyflyby-1.10.0 → pyflyby-1.10.2}/doc/cli/prune_broken_imports.rst +0 -0
- {pyflyby-1.10.0 → pyflyby-1.10.2}/doc/cli/py.rst +0 -0
- {pyflyby-1.10.0 → pyflyby-1.10.2}/doc/cli/pyflyby_diff.rst +0 -0
- {pyflyby-1.10.0 → pyflyby-1.10.2}/doc/cli/reformat_imports.rst +0 -0
- {pyflyby-1.10.0 → pyflyby-1.10.2}/doc/cli/replace_star_imports.rst +0 -0
- {pyflyby-1.10.0 → pyflyby-1.10.2}/doc/cli/tidy_imports.rst +0 -0
- {pyflyby-1.10.0 → pyflyby-1.10.2}/doc/cli/transform_imports.rst +0 -0
- {pyflyby-1.10.0 → pyflyby-1.10.2}/doc/index.rst +0 -0
- {pyflyby-1.10.0 → pyflyby-1.10.2}/doc/make.bat +0 -0
- {pyflyby-1.10.0 → pyflyby-1.10.2}/doc/testing.txt +0 -0
- {pyflyby-1.10.0 → pyflyby-1.10.2}/etc/pyflyby/.gitignore +0 -0
- {pyflyby-1.10.0 → pyflyby-1.10.2}/etc/pyflyby/canonical.py +0 -0
- {pyflyby-1.10.0 → pyflyby-1.10.2}/etc/pyflyby/common.py +0 -0
- {pyflyby-1.10.0 → pyflyby-1.10.2}/etc/pyflyby/forget.py +0 -0
- {pyflyby-1.10.0 → pyflyby-1.10.2}/etc/pyflyby/mandatory.py +0 -0
- {pyflyby-1.10.0 → pyflyby-1.10.2}/etc/pyflyby/numpy.py +0 -0
- {pyflyby-1.10.0 → pyflyby-1.10.2}/etc/pyflyby/std.py +0 -0
- {pyflyby-1.10.0 → pyflyby-1.10.2}/github_deploy_key_deshaw_pyflyby.enc +0 -0
- {pyflyby-1.10.0 → pyflyby-1.10.2}/lib/emacs/pyflyby.el +0 -0
- {pyflyby-1.10.0 → pyflyby-1.10.2}/lib/python/.gitignore +0 -0
- {pyflyby-1.10.0 → pyflyby-1.10.2}/lib/python/pyflyby/.gitignore +0 -0
- {pyflyby-1.10.0 → pyflyby-1.10.2}/lib/python/pyflyby/__init__.py +0 -0
- {pyflyby-1.10.0 → pyflyby-1.10.2}/lib/python/pyflyby/__main__.py +0 -0
- {pyflyby-1.10.0 → pyflyby-1.10.2}/lib/python/pyflyby/_autoimp.py +0 -0
- {pyflyby-1.10.0 → pyflyby-1.10.2}/lib/python/pyflyby/_comms.py +0 -0
- {pyflyby-1.10.0 → pyflyby-1.10.2}/lib/python/pyflyby/_dbg.py +0 -0
- {pyflyby-1.10.0 → pyflyby-1.10.2}/lib/python/pyflyby/_docxref.py +0 -0
- {pyflyby-1.10.0 → pyflyby-1.10.2}/lib/python/pyflyby/_dynimp.py +0 -0
- {pyflyby-1.10.0 → pyflyby-1.10.2}/lib/python/pyflyby/_file.py +0 -0
- {pyflyby-1.10.0 → pyflyby-1.10.2}/lib/python/pyflyby/_flags.py +0 -0
- {pyflyby-1.10.0 → pyflyby-1.10.2}/lib/python/pyflyby/_format.py +0 -0
- {pyflyby-1.10.0 → pyflyby-1.10.2}/lib/python/pyflyby/_idents.py +0 -0
- {pyflyby-1.10.0 → pyflyby-1.10.2}/lib/python/pyflyby/_import_sorting.py +0 -0
- {pyflyby-1.10.0 → pyflyby-1.10.2}/lib/python/pyflyby/_importclns.py +0 -0
- {pyflyby-1.10.0 → pyflyby-1.10.2}/lib/python/pyflyby/_importdb.py +0 -0
- {pyflyby-1.10.0 → pyflyby-1.10.2}/lib/python/pyflyby/_imports2s.py +0 -0
- {pyflyby-1.10.0 → pyflyby-1.10.2}/lib/python/pyflyby/_importstmt.py +0 -0
- {pyflyby-1.10.0 → pyflyby-1.10.2}/lib/python/pyflyby/_livepatch.py +0 -0
- {pyflyby-1.10.0 → pyflyby-1.10.2}/lib/python/pyflyby/_log.py +0 -0
- {pyflyby-1.10.0 → pyflyby-1.10.2}/lib/python/pyflyby/_parse.py +0 -0
- {pyflyby-1.10.0 → pyflyby-1.10.2}/lib/python/pyflyby/_py.py +0 -0
- {pyflyby-1.10.0 → pyflyby-1.10.2}/lib/python/pyflyby/_saveframe.py +0 -0
- {pyflyby-1.10.0 → pyflyby-1.10.2}/lib/python/pyflyby/_saveframe_reader.py +0 -0
- {pyflyby-1.10.0 → pyflyby-1.10.2}/lib/python/pyflyby/_util.py +0 -0
- {pyflyby-1.10.0 → pyflyby-1.10.2}/lib/python/pyflyby/autoimport.py +0 -0
- {pyflyby-1.10.0 → pyflyby-1.10.2}/lib/python/pyflyby/importdb.py +0 -0
- {pyflyby-1.10.0 → pyflyby-1.10.2}/lib/python/pyflyby/meson.build +0 -0
- {pyflyby-1.10.0 → pyflyby-1.10.2}/libexec/pyflyby/colordiff +0 -0
- {pyflyby-1.10.0 → pyflyby-1.10.2}/libexec/pyflyby/diff-colorize +0 -0
- {pyflyby-1.10.0 → pyflyby-1.10.2}/pytest.ini +0 -0
- {pyflyby-1.10.0 → pyflyby-1.10.2}/tests/__init__.py +0 -0
- {pyflyby-1.10.0 → pyflyby-1.10.2}/tests/test_0testconfig.py +0 -0
- {pyflyby-1.10.0 → pyflyby-1.10.2}/tests/test_autoimp.py +0 -0
- {pyflyby-1.10.0 → pyflyby-1.10.2}/tests/test_docxref.py +0 -0
- {pyflyby-1.10.0 → pyflyby-1.10.2}/tests/test_file.py +0 -0
- {pyflyby-1.10.0 → pyflyby-1.10.2}/tests/test_flags.py +0 -0
- {pyflyby-1.10.0 → pyflyby-1.10.2}/tests/test_format.py +0 -0
- {pyflyby-1.10.0 → pyflyby-1.10.2}/tests/test_idents.py +0 -0
- {pyflyby-1.10.0 → pyflyby-1.10.2}/tests/test_importclns.py +0 -0
- {pyflyby-1.10.0 → pyflyby-1.10.2}/tests/test_importdb.py +0 -0
- {pyflyby-1.10.0 → pyflyby-1.10.2}/tests/test_imports2s.py +0 -0
- {pyflyby-1.10.0 → pyflyby-1.10.2}/tests/test_importstmt.py +0 -0
- {pyflyby-1.10.0 → pyflyby-1.10.2}/tests/test_interactive.py +0 -0
- {pyflyby-1.10.0 → pyflyby-1.10.2}/tests/test_jupyterlab_pyflyby.py +0 -0
- {pyflyby-1.10.0 → pyflyby-1.10.2}/tests/test_livepatch.py +0 -0
- {pyflyby-1.10.0 → pyflyby-1.10.2}/tests/test_parse.py +0 -0
- {pyflyby-1.10.0 → pyflyby-1.10.2}/tests/test_py.py +0 -0
- {pyflyby-1.10.0 → pyflyby-1.10.2}/tests/test_saveframe.py +0 -0
- {pyflyby-1.10.0 → pyflyby-1.10.2}/tests/test_saveframe_reader.py +0 -0
- {pyflyby-1.10.0 → pyflyby-1.10.2}/tests/test_util.py +0 -0
- {pyflyby-1.10.0 → pyflyby-1.10.2}/tests/tests_sorts.py +0 -0
- {pyflyby-1.10.0 → pyflyby-1.10.2}/tests/xrefs.py +0 -0
- {pyflyby-1.10.0 → pyflyby-1.10.2}/tox.ini +0 -0
|
@@ -8,7 +8,7 @@ jobs:
|
|
|
8
8
|
steps:
|
|
9
9
|
- uses: actions/checkout@v5
|
|
10
10
|
- name: Set up Python
|
|
11
|
-
uses: actions/setup-python@
|
|
11
|
+
uses: actions/setup-python@v6
|
|
12
12
|
with:
|
|
13
13
|
python-version: 3.13
|
|
14
14
|
- name: Install pyflyby
|
|
@@ -17,7 +17,6 @@ jobs:
|
|
|
17
17
|
# https://mesonbuild.com/meson-python/how-to-guides/editable-installs.html#build-dependencies
|
|
18
18
|
# for details.
|
|
19
19
|
pip install meson-python meson ninja pybind11>=2.10.4
|
|
20
|
-
pip install setuptools wheel # needed for epydoc
|
|
21
20
|
pip install --no-build-isolation -ve . --group lint
|
|
22
21
|
- name: Mypy
|
|
23
22
|
run: |
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: pyflyby
|
|
3
|
-
Version: 1.10.
|
|
3
|
+
Version: 1.10.2
|
|
4
4
|
Summary: pyflyby - Python development productivity tools, in particular automatic import management
|
|
5
5
|
Author-Email: Karl Chen <quarl@8166.clguba.z.quarl.org>
|
|
6
6
|
License-Expression: MIT
|
|
@@ -20,9 +20,7 @@ Requires-Dist: six
|
|
|
20
20
|
Requires-Dist: tomli; python_version < "3.11"
|
|
21
21
|
Requires-Dist: typing_extensions>=4.6; python_version < "3.12"
|
|
22
22
|
Requires-Dist: prompt_toolkit
|
|
23
|
-
Requires-Dist:
|
|
24
|
-
Requires-Dist: wheel
|
|
25
|
-
Requires-Dist: appdirs
|
|
23
|
+
Requires-Dist: platformdirs
|
|
26
24
|
Provides-Extra: test
|
|
27
25
|
Requires-Dist: build; extra == "test"
|
|
28
26
|
Requires-Dist: coverage; extra == "test"
|
|
@@ -38,6 +36,9 @@ Requires-Dist: pytest-cov; extra == "test"
|
|
|
38
36
|
Requires-Dist: pytest-json-report; extra == "test"
|
|
39
37
|
Requires-Dist: pytest<=8; extra == "test"
|
|
40
38
|
Requires-Dist: requests; extra == "test"
|
|
39
|
+
Requires-Dist: epydoc; extra == "test"
|
|
40
|
+
Requires-Dist: wheel; extra == "test"
|
|
41
|
+
Requires-Dist: setuptools; extra == "test"
|
|
41
42
|
Description-Content-Type: text/x-rst
|
|
42
43
|
|
|
43
44
|
#########
|
|
@@ -209,6 +210,7 @@ For example:
|
|
|
209
210
|
|
|
210
211
|
Replace /tmp/foo.py? [y/N]
|
|
211
212
|
|
|
213
|
+
To exclude a file, use `--exclude <pattern>`.
|
|
212
214
|
|
|
213
215
|
Quick start: import libraries
|
|
214
216
|
=============================
|
|
@@ -480,21 +482,37 @@ Per-Project configuration of tidy-imports
|
|
|
480
482
|
=========================================
|
|
481
483
|
|
|
482
484
|
You can configure Pyflyby on a per-repository basis by using the
|
|
483
|
-
|
|
484
|
-
working directory and all it's parent until it find a
|
|
485
|
+
``[tool.pyflyby]`` section of ``pyproject.toml`` files. Pyflyby will look in current
|
|
486
|
+
working directory and all it's parent until it find a ``pyproject.toml`` file from
|
|
485
487
|
which it will load the defaults.
|
|
486
488
|
|
|
487
489
|
|
|
488
490
|
Most of the long command line flags default values can be configured in this
|
|
489
|
-
section. Simply use the long form option name by replacing dashes
|
|
490
|
-
underscore
|
|
491
|
-
can assign a boolean to
|
|
491
|
+
section. Simply use the long form option name by replacing dashes ``-`` by
|
|
492
|
+
underscore ``_``. For long option that have the form ``--xxx`` and ``--no-xxx``, you
|
|
493
|
+
can assign a boolean to ``xxx``. For example::
|
|
494
|
+
|
|
495
|
+
.. code:: toml
|
|
492
496
|
|
|
493
497
|
[tool.pyflyby]
|
|
494
498
|
add_missing=true
|
|
495
499
|
from_spaces=7
|
|
496
500
|
remove_unused=false
|
|
497
501
|
|
|
502
|
+
To exclude files from ``tidy-imports``, add an exclusion pattern to
|
|
503
|
+
``tool.pyflyby.tidy-imports.exclude``:
|
|
504
|
+
|
|
505
|
+
.. code:: toml
|
|
506
|
+
|
|
507
|
+
[tool.pyflyby.tidy-imports]
|
|
508
|
+
exclude = [
|
|
509
|
+
"foo.py",
|
|
510
|
+
"baz/*.py"
|
|
511
|
+
]
|
|
512
|
+
|
|
513
|
+
Exclusions are assumed to be relative to the project root if a ``pyproject.toml`` exists, unless an
|
|
514
|
+
absolute path is specified. Consult the documentation for ``pathlib.Path.match`` for information about
|
|
515
|
+
valid exclusion patterns.
|
|
498
516
|
|
|
499
517
|
Emacs support
|
|
500
518
|
=============
|
|
@@ -167,6 +167,7 @@ For example:
|
|
|
167
167
|
|
|
168
168
|
Replace /tmp/foo.py? [y/N]
|
|
169
169
|
|
|
170
|
+
To exclude a file, use `--exclude <pattern>`.
|
|
170
171
|
|
|
171
172
|
Quick start: import libraries
|
|
172
173
|
=============================
|
|
@@ -438,21 +439,37 @@ Per-Project configuration of tidy-imports
|
|
|
438
439
|
=========================================
|
|
439
440
|
|
|
440
441
|
You can configure Pyflyby on a per-repository basis by using the
|
|
441
|
-
|
|
442
|
-
working directory and all it's parent until it find a
|
|
442
|
+
``[tool.pyflyby]`` section of ``pyproject.toml`` files. Pyflyby will look in current
|
|
443
|
+
working directory and all it's parent until it find a ``pyproject.toml`` file from
|
|
443
444
|
which it will load the defaults.
|
|
444
445
|
|
|
445
446
|
|
|
446
447
|
Most of the long command line flags default values can be configured in this
|
|
447
|
-
section. Simply use the long form option name by replacing dashes
|
|
448
|
-
underscore
|
|
449
|
-
can assign a boolean to
|
|
448
|
+
section. Simply use the long form option name by replacing dashes ``-`` by
|
|
449
|
+
underscore ``_``. For long option that have the form ``--xxx`` and ``--no-xxx``, you
|
|
450
|
+
can assign a boolean to ``xxx``. For example::
|
|
451
|
+
|
|
452
|
+
.. code:: toml
|
|
450
453
|
|
|
451
454
|
[tool.pyflyby]
|
|
452
455
|
add_missing=true
|
|
453
456
|
from_spaces=7
|
|
454
457
|
remove_unused=false
|
|
455
458
|
|
|
459
|
+
To exclude files from ``tidy-imports``, add an exclusion pattern to
|
|
460
|
+
``tool.pyflyby.tidy-imports.exclude``:
|
|
461
|
+
|
|
462
|
+
.. code:: toml
|
|
463
|
+
|
|
464
|
+
[tool.pyflyby.tidy-imports]
|
|
465
|
+
exclude = [
|
|
466
|
+
"foo.py",
|
|
467
|
+
"baz/*.py"
|
|
468
|
+
]
|
|
469
|
+
|
|
470
|
+
Exclusions are assumed to be relative to the project root if a ``pyproject.toml`` exists, unless an
|
|
471
|
+
absolute path is specified. Consult the documentation for ``pathlib.Path.match`` for information about
|
|
472
|
+
valid exclusion patterns.
|
|
456
473
|
|
|
457
474
|
Emacs support
|
|
458
475
|
=============
|
|
@@ -85,6 +85,8 @@ def _addopts(parser):
|
|
|
85
85
|
default=True, action='store_false',
|
|
86
86
|
help=hfmt('''
|
|
87
87
|
Don't canonicalize imports.'''))
|
|
88
|
+
parser.add_option('--exclude', type='string', dest='exclude',
|
|
89
|
+
action='append', help=hfmt('Files to exclude from formatting.'))
|
|
88
90
|
|
|
89
91
|
|
|
90
92
|
def transform_callback(option, opt_str, value, group):
|
|
@@ -156,7 +158,12 @@ def main() -> None:
|
|
|
156
158
|
cannonical_imports = sorted_imports
|
|
157
159
|
return cannonical_imports
|
|
158
160
|
|
|
159
|
-
|
|
161
|
+
cmdline_exclude = getattr(options, "exclude")
|
|
162
|
+
process_actions(
|
|
163
|
+
args,
|
|
164
|
+
options.actions, modify,
|
|
165
|
+
exclude=default_config.get('tidy-imports', {}).get('exclude', []) + (cmdline_exclude if cmdline_exclude else [])
|
|
166
|
+
)
|
|
160
167
|
|
|
161
168
|
|
|
162
169
|
if __name__ == '__main__':
|
|
@@ -27,6 +27,10 @@ else:
|
|
|
27
27
|
from tomllib import loads
|
|
28
28
|
|
|
29
29
|
|
|
30
|
+
class ConfigurationError(Exception):
|
|
31
|
+
"""Exception class indicating a configuration error."""
|
|
32
|
+
|
|
33
|
+
|
|
30
34
|
def hfmt(s):
|
|
31
35
|
return dedent(s).strip()
|
|
32
36
|
|
|
@@ -232,26 +236,17 @@ def parse_args(addopts=None, import_format_params=False, modify_action_params=Fa
|
|
|
232
236
|
only if it is necessary to prevent exceeding the
|
|
233
237
|
width (by default 79).
|
|
234
238
|
'''))
|
|
235
|
-
|
|
236
|
-
parser.values.separate_from_imports = False
|
|
237
|
-
parser.values.from_spaces = 3
|
|
238
|
-
parser.values.align_imports = '32'
|
|
239
|
-
group.add_option('--uniform', '-u', action="callback",
|
|
240
|
-
callback=uniform_callback,
|
|
239
|
+
group.add_option('--uniform', '-u', action="store_true",
|
|
241
240
|
help=hfmt('''
|
|
242
241
|
(Default) Shortcut for --no-separate-from-imports
|
|
243
242
|
--from-spaces=3 --align-imports=32.'''))
|
|
244
|
-
|
|
245
|
-
parser.values.separate_from_imports = True
|
|
246
|
-
parser.values.from_spaces = 1
|
|
247
|
-
parser.values.align_imports = '0'
|
|
248
|
-
group.add_option('--unaligned', '-n', action="callback",
|
|
249
|
-
callback=unaligned_callback,
|
|
243
|
+
group.add_option('--unaligned', '-n', action="store_true",
|
|
250
244
|
help=hfmt('''
|
|
251
245
|
Shortcut for --separate-from-imports
|
|
252
246
|
--from-spaces=1 --align-imports=0.'''))
|
|
253
247
|
|
|
254
248
|
parser.add_option_group(group)
|
|
249
|
+
|
|
255
250
|
if addopts is not None:
|
|
256
251
|
addopts(parser)
|
|
257
252
|
# This is the only way to provide a default value for an option with a
|
|
@@ -260,7 +255,22 @@ def parse_args(addopts=None, import_format_params=False, modify_action_params=Fa
|
|
|
260
255
|
args = ["--symlinks=error"] + sys.argv[1:]
|
|
261
256
|
else:
|
|
262
257
|
args = None
|
|
258
|
+
|
|
263
259
|
options, args = parser.parse_args(args=args)
|
|
260
|
+
|
|
261
|
+
# Set these manually rather than in a callback option because callback
|
|
262
|
+
# options don't get triggered by OptionParser.set_default (which is
|
|
263
|
+
# used when setting values via pyproject.toml)
|
|
264
|
+
if getattr(options, "unaligned", False):
|
|
265
|
+
parser.values.separate_from_imports = True
|
|
266
|
+
parser.values.from_spaces = 1
|
|
267
|
+
parser.values.align_imports = '0'
|
|
268
|
+
|
|
269
|
+
if getattr(options, "uniform", False):
|
|
270
|
+
parser.values.separate_from_imports = False
|
|
271
|
+
parser.values.from_spaces = 3
|
|
272
|
+
parser.values.align_imports = '32'
|
|
273
|
+
|
|
264
274
|
if import_format_params:
|
|
265
275
|
align_imports_args = [int(x.strip())
|
|
266
276
|
for x in options.align_imports.split(",")]
|
|
@@ -380,14 +390,35 @@ class Modifier(object):
|
|
|
380
390
|
|
|
381
391
|
|
|
382
392
|
def process_actions(filenames:List[str], actions, modify_function,
|
|
383
|
-
reraise_exceptions=()):
|
|
393
|
+
reraise_exceptions=(), exclude=()):
|
|
394
|
+
|
|
395
|
+
if not isinstance(exclude, (list, tuple)):
|
|
396
|
+
raise ConfigurationError(
|
|
397
|
+
"Exclusions must be a list of filenames/patterns to exclude."
|
|
398
|
+
)
|
|
399
|
+
|
|
384
400
|
errors = []
|
|
385
401
|
def on_error_filename_arg(arg):
|
|
386
402
|
print("%s: bad filename %s" % (sys.argv[0], arg), file=sys.stderr)
|
|
387
403
|
errors.append("%s: bad filename" % (arg,))
|
|
388
|
-
|
|
404
|
+
filename_objs = filename_args(filenames, on_error=on_error_filename_arg)
|
|
389
405
|
exit_code = 0
|
|
390
|
-
for filename in
|
|
406
|
+
for filename in filename_objs:
|
|
407
|
+
|
|
408
|
+
# Log any matching exclusion patterns before ignoring, if applicable
|
|
409
|
+
matching_excludes = []
|
|
410
|
+
for pattern in exclude:
|
|
411
|
+
if Path(str(filename)).match(str(pattern)):
|
|
412
|
+
matching_excludes.append(pattern)
|
|
413
|
+
if any(matching_excludes):
|
|
414
|
+
msg = f"{filename} matches exclusion pattern"
|
|
415
|
+
if len(matching_excludes) == 1:
|
|
416
|
+
msg += f": {matching_excludes[0]}"
|
|
417
|
+
else:
|
|
418
|
+
msg += f"s: {matching_excludes}"
|
|
419
|
+
logger.info(msg)
|
|
420
|
+
continue
|
|
421
|
+
|
|
391
422
|
try:
|
|
392
423
|
m = Modifier(modify_function, filename)
|
|
393
424
|
for action in actions:
|
|
@@ -533,16 +564,28 @@ symlink_callbacks = {
|
|
|
533
564
|
'replace': symlink_replace,
|
|
534
565
|
}
|
|
535
566
|
|
|
536
|
-
def
|
|
537
|
-
"""
|
|
538
|
-
Try to find current project pyproject.toml
|
|
567
|
+
def _get_pyproj_toml_file():
|
|
568
|
+
"""Try to find the location of the current project pyproject.toml
|
|
539
569
|
in cwd or parents directories.
|
|
570
|
+
|
|
571
|
+
If no pyproject.toml can be found, None is returned.
|
|
540
572
|
"""
|
|
541
573
|
cwd = Path(os.getcwd())
|
|
542
574
|
|
|
543
575
|
for pth in [cwd] + list(cwd.parents):
|
|
544
576
|
pyproj_toml = pth /'pyproject.toml'
|
|
545
577
|
if pyproj_toml.exists() and pyproj_toml.is_file():
|
|
546
|
-
return
|
|
578
|
+
return pyproj_toml
|
|
547
579
|
|
|
548
580
|
return None
|
|
581
|
+
|
|
582
|
+
def _get_pyproj_toml_config():
|
|
583
|
+
"""Return the toml contents of the current pyproject.toml.
|
|
584
|
+
|
|
585
|
+
If no pyproject.toml can be found in cwd or parent directories,
|
|
586
|
+
None is returned.
|
|
587
|
+
"""
|
|
588
|
+
pyproject_toml = _get_pyproj_toml_file()
|
|
589
|
+
if pyproject_toml is not None:
|
|
590
|
+
return loads(pyproject_toml.read_text())
|
|
591
|
+
return None
|
|
@@ -1724,14 +1724,14 @@ class AutoImporter:
|
|
|
1724
1724
|
return __original__.fget(completer) + [completer.python_matcher]
|
|
1725
1725
|
|
|
1726
1726
|
@self._advise(completer.global_matches)
|
|
1727
|
-
def global_matches_with_autoimport(name):
|
|
1727
|
+
def global_matches_with_autoimport(name, *args, **kwargs):
|
|
1728
1728
|
old_global_namespace = completer.global_namespace
|
|
1729
1729
|
completer.global_namespace = NamespaceWithPotentialImports(
|
|
1730
1730
|
old_global_namespace,
|
|
1731
1731
|
ip=self._ip
|
|
1732
1732
|
)
|
|
1733
1733
|
try:
|
|
1734
|
-
return self._safe_call(__original__, name)
|
|
1734
|
+
return self._safe_call(__original__, name, *args, **kwargs)
|
|
1735
1735
|
finally:
|
|
1736
1736
|
completer.global_namespace = old_global_namespace
|
|
1737
1737
|
|
|
@@ -4,7 +4,6 @@
|
|
|
4
4
|
|
|
5
5
|
from __future__ import annotations
|
|
6
6
|
|
|
7
|
-
import appdirs
|
|
8
7
|
import ast
|
|
9
8
|
from functools import cached_property, total_ordering
|
|
10
9
|
import hashlib
|
|
@@ -14,6 +13,7 @@ import json
|
|
|
14
13
|
import os
|
|
15
14
|
import pathlib
|
|
16
15
|
import pkgutil
|
|
16
|
+
import platformdirs
|
|
17
17
|
import textwrap
|
|
18
18
|
|
|
19
19
|
from pyflyby._fast_iter_modules \
|
|
@@ -45,7 +45,7 @@ def rebuild_import_cache():
|
|
|
45
45
|
The cache is deleted before calling _fast_iter_modules, which repopulates the cache.
|
|
46
46
|
"""
|
|
47
47
|
for path in pathlib.Path(
|
|
48
|
-
|
|
48
|
+
platformdirs.user_cache_dir(appname='pyflyby', appauthor=False)
|
|
49
49
|
).iterdir():
|
|
50
50
|
_remove_import_cache_dir(path)
|
|
51
51
|
_fast_iter_modules()
|
|
@@ -595,8 +595,14 @@ def _cached_module_finder(
|
|
|
595
595
|
Tuples containing (prefix+module name, a bool indicating whether the module is a
|
|
596
596
|
package or not)
|
|
597
597
|
"""
|
|
598
|
+
if os.environ.get("PYFLYBY_DISABLE_CACHE", "0") == "1":
|
|
599
|
+
modules = _iter_file_finder_modules(importer, SUFFIXES)
|
|
600
|
+
for module, ispkg in modules:
|
|
601
|
+
yield prefix + module, ispkg
|
|
602
|
+
return
|
|
603
|
+
|
|
598
604
|
cache_dir = pathlib.Path(
|
|
599
|
-
|
|
605
|
+
platformdirs.user_cache_dir(appname='pyflyby', appauthor=False)
|
|
600
606
|
) / hashlib.sha256(str(importer.path).encode()).hexdigest()
|
|
601
607
|
cache_file = cache_dir / str(os.stat(importer.path).st_mtime_ns)
|
|
602
608
|
|
|
@@ -610,7 +616,7 @@ def _cached_module_finder(
|
|
|
610
616
|
for path in cache_dir.iterdir():
|
|
611
617
|
_remove_import_cache_dir(path)
|
|
612
618
|
|
|
613
|
-
if os.environ.get("PYFLYBY_SUPPRESS_CACHE_REBUILD_LOGS",
|
|
619
|
+
if os.environ.get("PYFLYBY_SUPPRESS_CACHE_REBUILD_LOGS", "1") != "1":
|
|
614
620
|
logger.info(f"Rebuilding cache for {_format_path(importer.path)}...")
|
|
615
621
|
|
|
616
622
|
modules = _iter_file_finder_modules(importer, SUFFIXES)
|
|
@@ -30,9 +30,7 @@ dependencies = [
|
|
|
30
30
|
"tomli; python_version<'3.11'",
|
|
31
31
|
"typing_extensions>=4.6; python_version<'3.12'",
|
|
32
32
|
'prompt_toolkit',
|
|
33
|
-
'
|
|
34
|
-
'wheel', # required by epydoc, but not listed as a dependency
|
|
35
|
-
'appdirs',
|
|
33
|
+
'platformdirs',
|
|
36
34
|
]
|
|
37
35
|
[project.urls]
|
|
38
36
|
Homepage = "https://pypi.org/project/pyflyby/"
|
|
@@ -59,6 +57,9 @@ test = [
|
|
|
59
57
|
'pytest-json-report',
|
|
60
58
|
'pytest<=8',
|
|
61
59
|
'requests',
|
|
60
|
+
'epydoc',
|
|
61
|
+
'wheel', # required by epydoc, but not listed as a dependency
|
|
62
|
+
'setuptools', # required by epydoc, but not listed as a dependency
|
|
62
63
|
]
|
|
63
64
|
|
|
64
65
|
[dependency-groups]
|
|
@@ -62,24 +62,35 @@ _iter_file_finder_modules(
|
|
|
62
62
|
return ret;
|
|
63
63
|
}
|
|
64
64
|
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
65
|
+
// Attempt to iterate the directory. If the directory is unreadable for any reason
|
|
66
|
+
// (e.g., permissions, non-existent, or other system errors), fs::directory_iterator
|
|
67
|
+
// will throw a filesystem_error. We catch this and return an empty list for this path.
|
|
68
|
+
try {
|
|
69
|
+
for (auto const &entry : fs::directory_iterator(path)) {
|
|
70
|
+
fs::path entry_path = entry.path();
|
|
71
|
+
fs::path filename = entry_path.filename();
|
|
72
|
+
std::string modname = getmodulename(filename, suffixes);
|
|
69
73
|
|
|
70
74
|
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
75
|
+
if (modname == "" && fs::is_directory(entry_path) &&
|
|
76
|
+
filename.string().find(".") == std::string::npos &&
|
|
77
|
+
fs::is_regular_file(entry_path / "__init__.py") // Is this a package?
|
|
78
|
+
) {
|
|
79
|
+
ret.push_back(std::make_tuple(filename.string(), true));
|
|
80
|
+
} else if (modname == "__init__") {
|
|
81
|
+
continue;
|
|
82
|
+
} else if (modname != "" && modname.find(".") == std::string::npos) {
|
|
83
|
+
ret.push_back(std::make_tuple(modname,
|
|
84
|
+
false // This is definitely not a package
|
|
85
|
+
));
|
|
86
|
+
}
|
|
82
87
|
}
|
|
88
|
+
} catch (const fs::filesystem_error& e) {
|
|
89
|
+
// If an error occurs during directory iteration (e.g., permissions denied,
|
|
90
|
+
// directory removed concurrently), we treat it as unreadable/inaccessible
|
|
91
|
+
// and return the current (potentially empty) list, effectively skipping this path.
|
|
92
|
+
// We could log the error 'e.what()' here if desired for debugging.
|
|
93
|
+
return ret;
|
|
83
94
|
}
|
|
84
95
|
|
|
85
96
|
return ret;
|