pyflyby 1.10.1__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.1 → pyflyby-1.10.2}/.github/workflows/docs.yml +1 -1
- {pyflyby-1.10.1 → pyflyby-1.10.2}/.github/workflows/lint.yml +1 -1
- {pyflyby-1.10.1 → pyflyby-1.10.2}/.github/workflows/test.yml +1 -1
- {pyflyby-1.10.1 → pyflyby-1.10.2}/PKG-INFO +23 -6
- {pyflyby-1.10.1 → pyflyby-1.10.2}/README.rst +22 -5
- {pyflyby-1.10.1 → pyflyby-1.10.2}/bin/tidy-imports +8 -1
- {pyflyby-1.10.1 → pyflyby-1.10.2}/lib/python/pyflyby/_cmdline.py +62 -19
- {pyflyby-1.10.1 → pyflyby-1.10.2}/lib/python/pyflyby/_modules.py +7 -1
- {pyflyby-1.10.1 → pyflyby-1.10.2}/lib/python/pyflyby/_version.py +1 -1
- {pyflyby-1.10.1 → pyflyby-1.10.2}/meson.build +1 -1
- {pyflyby-1.10.1 → pyflyby-1.10.2}/src/_fast_iter_modules.cpp +26 -15
- {pyflyby-1.10.1 → pyflyby-1.10.2}/tests/test_cmdline.py +261 -1
- {pyflyby-1.10.1 → pyflyby-1.10.2}/tests/test_modules.py +20 -1
- {pyflyby-1.10.1 → pyflyby-1.10.2}/.github/dependabot.yml +0 -0
- {pyflyby-1.10.1 → pyflyby-1.10.2}/.gitignore +0 -0
- {pyflyby-1.10.1 → pyflyby-1.10.2}/.pyflyby +0 -0
- {pyflyby-1.10.1 → pyflyby-1.10.2}/CONTRIBUTING.md +0 -0
- {pyflyby-1.10.1 → pyflyby-1.10.2}/LICENSE.txt +0 -0
- {pyflyby-1.10.1 → pyflyby-1.10.2}/MANIFEST.in +0 -0
- {pyflyby-1.10.1 → pyflyby-1.10.2}/bin/autoipython +0 -0
- {pyflyby-1.10.1 → pyflyby-1.10.2}/bin/autopython +0 -0
- {pyflyby-1.10.1 → pyflyby-1.10.2}/bin/collect-exports +0 -0
- {pyflyby-1.10.1 → pyflyby-1.10.2}/bin/collect-imports +0 -0
- {pyflyby-1.10.1 → pyflyby-1.10.2}/bin/create-imports +0 -0
- {pyflyby-1.10.1 → pyflyby-1.10.2}/bin/find-import +0 -0
- {pyflyby-1.10.1 → pyflyby-1.10.2}/bin/list-bad-xrefs +0 -0
- {pyflyby-1.10.1 → pyflyby-1.10.2}/bin/prune-broken-imports +0 -0
- {pyflyby-1.10.1 → pyflyby-1.10.2}/bin/py +0 -0
- {pyflyby-1.10.1 → pyflyby-1.10.2}/bin/pyflyby-diff +0 -0
- {pyflyby-1.10.1 → pyflyby-1.10.2}/bin/reformat-imports +0 -0
- {pyflyby-1.10.1 → pyflyby-1.10.2}/bin/replace-star-imports +0 -0
- {pyflyby-1.10.1 → pyflyby-1.10.2}/bin/saveframe +0 -0
- {pyflyby-1.10.1 → pyflyby-1.10.2}/bin/transform-imports +0 -0
- {pyflyby-1.10.1 → pyflyby-1.10.2}/codecov.yml +0 -0
- {pyflyby-1.10.1 → pyflyby-1.10.2}/conftest.py +0 -0
- {pyflyby-1.10.1 → pyflyby-1.10.2}/doc/LICENSE.txt +0 -0
- {pyflyby-1.10.1 → pyflyby-1.10.2}/doc/Makefile +0 -0
- {pyflyby-1.10.1 → pyflyby-1.10.2}/doc/TODO.txt +0 -0
- {pyflyby-1.10.1 → pyflyby-1.10.2}/doc/__init__.py +0 -0
- {pyflyby-1.10.1 → pyflyby-1.10.2}/doc/api/api.rst +0 -0
- {pyflyby-1.10.1 → pyflyby-1.10.2}/doc/api/autoimp.rst +0 -0
- {pyflyby-1.10.1 → pyflyby-1.10.2}/doc/api/cmdline.rst +0 -0
- {pyflyby-1.10.1 → pyflyby-1.10.2}/doc/api/comms.rst +0 -0
- {pyflyby-1.10.1 → pyflyby-1.10.2}/doc/api/dbg.rst +0 -0
- {pyflyby-1.10.1 → pyflyby-1.10.2}/doc/api/file.rst +0 -0
- {pyflyby-1.10.1 → pyflyby-1.10.2}/doc/api/flags.rst +0 -0
- {pyflyby-1.10.1 → pyflyby-1.10.2}/doc/api/format.rst +0 -0
- {pyflyby-1.10.1 → pyflyby-1.10.2}/doc/api/idents.rst +0 -0
- {pyflyby-1.10.1 → pyflyby-1.10.2}/doc/api/importclns.rst +0 -0
- {pyflyby-1.10.1 → pyflyby-1.10.2}/doc/api/importdb.rst +0 -0
- {pyflyby-1.10.1 → pyflyby-1.10.2}/doc/api/imports2s.rst +0 -0
- {pyflyby-1.10.1 → pyflyby-1.10.2}/doc/api/importstmt.rst +0 -0
- {pyflyby-1.10.1 → pyflyby-1.10.2}/doc/api/interactive.rst +0 -0
- {pyflyby-1.10.1 → pyflyby-1.10.2}/doc/api/livepatch.rst +0 -0
- {pyflyby-1.10.1 → pyflyby-1.10.2}/doc/api/log.rst +0 -0
- {pyflyby-1.10.1 → pyflyby-1.10.2}/doc/api/modules.rst +0 -0
- {pyflyby-1.10.1 → pyflyby-1.10.2}/doc/api/parse.rst +0 -0
- {pyflyby-1.10.1 → pyflyby-1.10.2}/doc/api/py.rst +0 -0
- {pyflyby-1.10.1 → pyflyby-1.10.2}/doc/api/util.rst +0 -0
- {pyflyby-1.10.1 → pyflyby-1.10.2}/doc/cli/autoipython.rst +0 -0
- {pyflyby-1.10.1 → pyflyby-1.10.2}/doc/cli/cli.rst +0 -0
- {pyflyby-1.10.1 → pyflyby-1.10.2}/doc/cli/collect_exports.rst +0 -0
- {pyflyby-1.10.1 → pyflyby-1.10.2}/doc/cli/collect_imports.rst +0 -0
- {pyflyby-1.10.1 → pyflyby-1.10.2}/doc/cli/find_import.rst +0 -0
- {pyflyby-1.10.1 → pyflyby-1.10.2}/doc/cli/prune_broken_imports.rst +0 -0
- {pyflyby-1.10.1 → pyflyby-1.10.2}/doc/cli/py.rst +0 -0
- {pyflyby-1.10.1 → pyflyby-1.10.2}/doc/cli/pyflyby_diff.rst +0 -0
- {pyflyby-1.10.1 → pyflyby-1.10.2}/doc/cli/reformat_imports.rst +0 -0
- {pyflyby-1.10.1 → pyflyby-1.10.2}/doc/cli/replace_star_imports.rst +0 -0
- {pyflyby-1.10.1 → pyflyby-1.10.2}/doc/cli/tidy_imports.rst +0 -0
- {pyflyby-1.10.1 → pyflyby-1.10.2}/doc/cli/transform_imports.rst +0 -0
- {pyflyby-1.10.1 → pyflyby-1.10.2}/doc/conf.py +0 -0
- {pyflyby-1.10.1 → pyflyby-1.10.2}/doc/index.rst +0 -0
- {pyflyby-1.10.1 → pyflyby-1.10.2}/doc/make.bat +0 -0
- {pyflyby-1.10.1 → pyflyby-1.10.2}/doc/testing.txt +0 -0
- {pyflyby-1.10.1 → pyflyby-1.10.2}/etc/pyflyby/.gitignore +0 -0
- {pyflyby-1.10.1 → pyflyby-1.10.2}/etc/pyflyby/canonical.py +0 -0
- {pyflyby-1.10.1 → pyflyby-1.10.2}/etc/pyflyby/common.py +0 -0
- {pyflyby-1.10.1 → pyflyby-1.10.2}/etc/pyflyby/forget.py +0 -0
- {pyflyby-1.10.1 → pyflyby-1.10.2}/etc/pyflyby/mandatory.py +0 -0
- {pyflyby-1.10.1 → pyflyby-1.10.2}/etc/pyflyby/numpy.py +0 -0
- {pyflyby-1.10.1 → pyflyby-1.10.2}/etc/pyflyby/std.py +0 -0
- {pyflyby-1.10.1 → pyflyby-1.10.2}/github_deploy_key_deshaw_pyflyby.enc +0 -0
- {pyflyby-1.10.1 → pyflyby-1.10.2}/lib/emacs/pyflyby.el +0 -0
- {pyflyby-1.10.1 → pyflyby-1.10.2}/lib/python/.gitignore +0 -0
- {pyflyby-1.10.1 → pyflyby-1.10.2}/lib/python/pyflyby/.gitignore +0 -0
- {pyflyby-1.10.1 → pyflyby-1.10.2}/lib/python/pyflyby/__init__.py +0 -0
- {pyflyby-1.10.1 → pyflyby-1.10.2}/lib/python/pyflyby/__main__.py +0 -0
- {pyflyby-1.10.1 → pyflyby-1.10.2}/lib/python/pyflyby/_autoimp.py +0 -0
- {pyflyby-1.10.1 → pyflyby-1.10.2}/lib/python/pyflyby/_comms.py +0 -0
- {pyflyby-1.10.1 → pyflyby-1.10.2}/lib/python/pyflyby/_dbg.py +0 -0
- {pyflyby-1.10.1 → pyflyby-1.10.2}/lib/python/pyflyby/_docxref.py +0 -0
- {pyflyby-1.10.1 → pyflyby-1.10.2}/lib/python/pyflyby/_dynimp.py +0 -0
- {pyflyby-1.10.1 → pyflyby-1.10.2}/lib/python/pyflyby/_file.py +0 -0
- {pyflyby-1.10.1 → pyflyby-1.10.2}/lib/python/pyflyby/_flags.py +0 -0
- {pyflyby-1.10.1 → pyflyby-1.10.2}/lib/python/pyflyby/_format.py +0 -0
- {pyflyby-1.10.1 → pyflyby-1.10.2}/lib/python/pyflyby/_idents.py +0 -0
- {pyflyby-1.10.1 → pyflyby-1.10.2}/lib/python/pyflyby/_import_sorting.py +0 -0
- {pyflyby-1.10.1 → pyflyby-1.10.2}/lib/python/pyflyby/_importclns.py +0 -0
- {pyflyby-1.10.1 → pyflyby-1.10.2}/lib/python/pyflyby/_importdb.py +0 -0
- {pyflyby-1.10.1 → pyflyby-1.10.2}/lib/python/pyflyby/_imports2s.py +0 -0
- {pyflyby-1.10.1 → pyflyby-1.10.2}/lib/python/pyflyby/_importstmt.py +0 -0
- {pyflyby-1.10.1 → pyflyby-1.10.2}/lib/python/pyflyby/_interactive.py +0 -0
- {pyflyby-1.10.1 → pyflyby-1.10.2}/lib/python/pyflyby/_livepatch.py +0 -0
- {pyflyby-1.10.1 → pyflyby-1.10.2}/lib/python/pyflyby/_log.py +0 -0
- {pyflyby-1.10.1 → pyflyby-1.10.2}/lib/python/pyflyby/_parse.py +0 -0
- {pyflyby-1.10.1 → pyflyby-1.10.2}/lib/python/pyflyby/_py.py +0 -0
- {pyflyby-1.10.1 → pyflyby-1.10.2}/lib/python/pyflyby/_saveframe.py +0 -0
- {pyflyby-1.10.1 → pyflyby-1.10.2}/lib/python/pyflyby/_saveframe_reader.py +0 -0
- {pyflyby-1.10.1 → pyflyby-1.10.2}/lib/python/pyflyby/_util.py +0 -0
- {pyflyby-1.10.1 → pyflyby-1.10.2}/lib/python/pyflyby/autoimport.py +0 -0
- {pyflyby-1.10.1 → pyflyby-1.10.2}/lib/python/pyflyby/importdb.py +0 -0
- {pyflyby-1.10.1 → pyflyby-1.10.2}/lib/python/pyflyby/meson.build +0 -0
- {pyflyby-1.10.1 → pyflyby-1.10.2}/libexec/pyflyby/colordiff +0 -0
- {pyflyby-1.10.1 → pyflyby-1.10.2}/libexec/pyflyby/diff-colorize +0 -0
- {pyflyby-1.10.1 → pyflyby-1.10.2}/pyproject.toml +0 -0
- {pyflyby-1.10.1 → pyflyby-1.10.2}/pytest.ini +0 -0
- {pyflyby-1.10.1 → pyflyby-1.10.2}/tests/__init__.py +0 -0
- {pyflyby-1.10.1 → pyflyby-1.10.2}/tests/test_0testconfig.py +0 -0
- {pyflyby-1.10.1 → pyflyby-1.10.2}/tests/test_autoimp.py +0 -0
- {pyflyby-1.10.1 → pyflyby-1.10.2}/tests/test_docxref.py +0 -0
- {pyflyby-1.10.1 → pyflyby-1.10.2}/tests/test_file.py +0 -0
- {pyflyby-1.10.1 → pyflyby-1.10.2}/tests/test_flags.py +0 -0
- {pyflyby-1.10.1 → pyflyby-1.10.2}/tests/test_format.py +0 -0
- {pyflyby-1.10.1 → pyflyby-1.10.2}/tests/test_idents.py +0 -0
- {pyflyby-1.10.1 → pyflyby-1.10.2}/tests/test_importclns.py +0 -0
- {pyflyby-1.10.1 → pyflyby-1.10.2}/tests/test_importdb.py +0 -0
- {pyflyby-1.10.1 → pyflyby-1.10.2}/tests/test_imports2s.py +0 -0
- {pyflyby-1.10.1 → pyflyby-1.10.2}/tests/test_importstmt.py +0 -0
- {pyflyby-1.10.1 → pyflyby-1.10.2}/tests/test_interactive.py +0 -0
- {pyflyby-1.10.1 → pyflyby-1.10.2}/tests/test_jupyterlab_pyflyby.py +0 -0
- {pyflyby-1.10.1 → pyflyby-1.10.2}/tests/test_livepatch.py +0 -0
- {pyflyby-1.10.1 → pyflyby-1.10.2}/tests/test_parse.py +0 -0
- {pyflyby-1.10.1 → pyflyby-1.10.2}/tests/test_py.py +0 -0
- {pyflyby-1.10.1 → pyflyby-1.10.2}/tests/test_saveframe.py +0 -0
- {pyflyby-1.10.1 → pyflyby-1.10.2}/tests/test_saveframe_reader.py +0 -0
- {pyflyby-1.10.1 → pyflyby-1.10.2}/tests/test_util.py +0 -0
- {pyflyby-1.10.1 → pyflyby-1.10.2}/tests/tests_sorts.py +0 -0
- {pyflyby-1.10.1 → pyflyby-1.10.2}/tests/xrefs.py +0 -0
- {pyflyby-1.10.1 → pyflyby-1.10.2}/tox.ini +0 -0
|
@@ -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
|
|
@@ -210,6 +210,7 @@ For example:
|
|
|
210
210
|
|
|
211
211
|
Replace /tmp/foo.py? [y/N]
|
|
212
212
|
|
|
213
|
+
To exclude a file, use `--exclude <pattern>`.
|
|
213
214
|
|
|
214
215
|
Quick start: import libraries
|
|
215
216
|
=============================
|
|
@@ -481,21 +482,37 @@ Per-Project configuration of tidy-imports
|
|
|
481
482
|
=========================================
|
|
482
483
|
|
|
483
484
|
You can configure Pyflyby on a per-repository basis by using the
|
|
484
|
-
|
|
485
|
-
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
|
|
486
487
|
which it will load the defaults.
|
|
487
488
|
|
|
488
489
|
|
|
489
490
|
Most of the long command line flags default values can be configured in this
|
|
490
|
-
section. Simply use the long form option name by replacing dashes
|
|
491
|
-
underscore
|
|
492
|
-
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
|
|
493
496
|
|
|
494
497
|
[tool.pyflyby]
|
|
495
498
|
add_missing=true
|
|
496
499
|
from_spaces=7
|
|
497
500
|
remove_unused=false
|
|
498
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.
|
|
499
516
|
|
|
500
517
|
Emacs support
|
|
501
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
|
|
@@ -595,6 +595,12 @@ 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()
|
|
@@ -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)
|
|
@@ -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;
|
|
@@ -934,7 +934,267 @@ def test_load_pyproject_toml(tmp_path, pyproject_text):
|
|
|
934
934
|
os.chdir(tmp_path)
|
|
935
935
|
assert _get_pyproj_toml_config() == loads(pyproject_text)
|
|
936
936
|
|
|
937
|
+
|
|
937
938
|
def test_load_no_pyproject_toml(tmp_path):
|
|
938
|
-
"""Test that a directory pyproject.toml
|
|
939
|
+
"""Test that a directory without a pyproject.toml is correctly handled."""
|
|
939
940
|
os.chdir(tmp_path)
|
|
940
941
|
assert _get_pyproj_toml_config() is None
|
|
942
|
+
|
|
943
|
+
|
|
944
|
+
def test_pyproject_unaligned(tmp_path):
|
|
945
|
+
"""Test that having an unaligned option in pyproject.toml works as intended."""
|
|
946
|
+
with open(tmp_path / 'pyproject.toml', 'w') as f:
|
|
947
|
+
f.write(
|
|
948
|
+
dedent(
|
|
949
|
+
"""
|
|
950
|
+
[tool.pyflyby]
|
|
951
|
+
remove_unused = false
|
|
952
|
+
add_mandatory = false
|
|
953
|
+
unaligned = true
|
|
954
|
+
"""
|
|
955
|
+
)
|
|
956
|
+
)
|
|
957
|
+
|
|
958
|
+
with open(tmp_path / "foo.py", 'w') as f:
|
|
959
|
+
f.write(
|
|
960
|
+
dedent(
|
|
961
|
+
"""
|
|
962
|
+
from math import pi
|
|
963
|
+
import numpy
|
|
964
|
+
from os import open
|
|
965
|
+
import pandas
|
|
966
|
+
from urllib import request
|
|
967
|
+
"""
|
|
968
|
+
)
|
|
969
|
+
)
|
|
970
|
+
|
|
971
|
+
child = pexpect.spawn(
|
|
972
|
+
python,
|
|
973
|
+
[BIN_DIR + "/tidy-imports", "./"],
|
|
974
|
+
timeout=5.0,
|
|
975
|
+
cwd=tmp_path,
|
|
976
|
+
logfile=BytesIO(),
|
|
977
|
+
)
|
|
978
|
+
child.expect_exact("foo.py? [y/N]")
|
|
979
|
+
child.send("y\n")
|
|
980
|
+
child.expect(pexpect.EOF)
|
|
981
|
+
|
|
982
|
+
with open(tmp_path / "foo.py") as f:
|
|
983
|
+
assert f.read() == dedent(
|
|
984
|
+
"""
|
|
985
|
+
import numpy
|
|
986
|
+
import pandas
|
|
987
|
+
from math import pi
|
|
988
|
+
from os import open
|
|
989
|
+
from urllib import request
|
|
990
|
+
"""
|
|
991
|
+
)
|
|
992
|
+
|
|
993
|
+
|
|
994
|
+
def test_no_unaligned(tmp_path):
|
|
995
|
+
"""Test that not having an unaligned option in pyproject.toml works as intended."""
|
|
996
|
+
with open(tmp_path / 'pyproject.toml', 'w') as f:
|
|
997
|
+
f.write(
|
|
998
|
+
dedent(
|
|
999
|
+
"""
|
|
1000
|
+
[tool.pyflyby]
|
|
1001
|
+
remove_unused = false
|
|
1002
|
+
add_mandatory = false
|
|
1003
|
+
"""
|
|
1004
|
+
)
|
|
1005
|
+
)
|
|
1006
|
+
|
|
1007
|
+
with open(tmp_path / "foo.py", 'w') as f:
|
|
1008
|
+
f.write(
|
|
1009
|
+
dedent(
|
|
1010
|
+
"""
|
|
1011
|
+
from math import pi
|
|
1012
|
+
import numpy
|
|
1013
|
+
from os import open
|
|
1014
|
+
import pandas
|
|
1015
|
+
from urllib import request
|
|
1016
|
+
"""
|
|
1017
|
+
)
|
|
1018
|
+
)
|
|
1019
|
+
|
|
1020
|
+
child = pexpect.spawn(
|
|
1021
|
+
python,
|
|
1022
|
+
[BIN_DIR + "/tidy-imports", "./"],
|
|
1023
|
+
timeout=5.0,
|
|
1024
|
+
cwd=tmp_path,
|
|
1025
|
+
logfile=BytesIO(),
|
|
1026
|
+
)
|
|
1027
|
+
child.expect_exact("foo.py? [y/N]")
|
|
1028
|
+
child.send("y\n")
|
|
1029
|
+
child.expect(pexpect.EOF)
|
|
1030
|
+
|
|
1031
|
+
with open(tmp_path / "foo.py") as f:
|
|
1032
|
+
assert f.read() == dedent(
|
|
1033
|
+
"""
|
|
1034
|
+
from math import pi
|
|
1035
|
+
import numpy
|
|
1036
|
+
from os import open
|
|
1037
|
+
import pandas
|
|
1038
|
+
from urllib import request
|
|
1039
|
+
"""
|
|
1040
|
+
)
|
|
1041
|
+
|
|
1042
|
+
|
|
1043
|
+
def test_tidy_imports_exclude_pyproject(tmp_path):
|
|
1044
|
+
"""Test that a pyproject.toml can be used to exclude files for tidy-imports."""
|
|
1045
|
+
with open(tmp_path / "pyproject.toml", 'w') as f:
|
|
1046
|
+
f.write(
|
|
1047
|
+
dedent(
|
|
1048
|
+
"""
|
|
1049
|
+
[tool.pyflyby.tidy-imports]
|
|
1050
|
+
exclude = [
|
|
1051
|
+
'foo.py',
|
|
1052
|
+
'bar/*.py',
|
|
1053
|
+
]
|
|
1054
|
+
"""
|
|
1055
|
+
)
|
|
1056
|
+
)
|
|
1057
|
+
|
|
1058
|
+
(tmp_path / "bar").mkdir()
|
|
1059
|
+
(tmp_path / "baz" / "blah").mkdir(parents=True)
|
|
1060
|
+
|
|
1061
|
+
txt = dedent(
|
|
1062
|
+
"""
|
|
1063
|
+
# hello
|
|
1064
|
+
def foo():
|
|
1065
|
+
foo() + os + sys
|
|
1066
|
+
"""
|
|
1067
|
+
)
|
|
1068
|
+
for path in [
|
|
1069
|
+
tmp_path / "foo.py",
|
|
1070
|
+
tmp_path / "what.py",
|
|
1071
|
+
tmp_path / "bar" / "foo2.py",
|
|
1072
|
+
tmp_path / "baz" / "foo3.py",
|
|
1073
|
+
]:
|
|
1074
|
+
with open(path, "w") as f:
|
|
1075
|
+
f.write(txt)
|
|
1076
|
+
|
|
1077
|
+
child = pexpect.spawn(
|
|
1078
|
+
python,
|
|
1079
|
+
[BIN_DIR+'/tidy-imports', './'],
|
|
1080
|
+
timeout=5.0,
|
|
1081
|
+
cwd=tmp_path,
|
|
1082
|
+
logfile=BytesIO()
|
|
1083
|
+
)
|
|
1084
|
+
child.expect_exact("baz/foo3.py? [y/N]")
|
|
1085
|
+
child.send("y\n")
|
|
1086
|
+
child.expect_exact("what.py? [y/N]")
|
|
1087
|
+
child.send("y\n")
|
|
1088
|
+
child.expect(pexpect.EOF)
|
|
1089
|
+
|
|
1090
|
+
# Check that the tidy-imports output has log messages about exclusion patterns
|
|
1091
|
+
output = child.logfile.getvalue().decode()
|
|
1092
|
+
assert "bar/foo2.py matches exclusion pattern: bar/*.py" in output
|
|
1093
|
+
assert "foo.py matches exclusion pattern: foo.py" in output
|
|
1094
|
+
|
|
1095
|
+
# Check that the two modified files have imports
|
|
1096
|
+
with open(tmp_path / "baz" / "foo3.py") as f:
|
|
1097
|
+
foo3 = f.read()
|
|
1098
|
+
|
|
1099
|
+
with open(tmp_path / "what.py") as f:
|
|
1100
|
+
what = f.read()
|
|
1101
|
+
|
|
1102
|
+
expected = dedent(
|
|
1103
|
+
"""
|
|
1104
|
+
# hello
|
|
1105
|
+
import os
|
|
1106
|
+
import sys
|
|
1107
|
+
|
|
1108
|
+
def foo():
|
|
1109
|
+
foo() + os + sys
|
|
1110
|
+
"""
|
|
1111
|
+
)
|
|
1112
|
+
assert foo3 == expected
|
|
1113
|
+
assert what == expected
|
|
1114
|
+
|
|
1115
|
+
# Check that the two unmodified files don't have imports
|
|
1116
|
+
with open(tmp_path / "foo.py") as f:
|
|
1117
|
+
foo = f.read()
|
|
1118
|
+
|
|
1119
|
+
with open(tmp_path / "bar" / "foo2.py") as f:
|
|
1120
|
+
foo2 = f.read()
|
|
1121
|
+
|
|
1122
|
+
assert foo == txt
|
|
1123
|
+
assert foo2 == txt
|
|
1124
|
+
|
|
1125
|
+
|
|
1126
|
+
def test_tidy_imports_exclude_arg(tmp_path):
|
|
1127
|
+
"""Test that a command line arg can be used to exclude files for tidy-imports."""
|
|
1128
|
+
(tmp_path / "bar").mkdir()
|
|
1129
|
+
(tmp_path / "baz" / "blah").mkdir(parents=True)
|
|
1130
|
+
|
|
1131
|
+
txt = dedent(
|
|
1132
|
+
"""
|
|
1133
|
+
# hello
|
|
1134
|
+
def foo():
|
|
1135
|
+
foo() + os + sys
|
|
1136
|
+
"""
|
|
1137
|
+
)
|
|
1138
|
+
for path in [
|
|
1139
|
+
tmp_path / "foo.py",
|
|
1140
|
+
tmp_path / "what.py",
|
|
1141
|
+
tmp_path / "bar" / "foo2.py",
|
|
1142
|
+
tmp_path / "baz" / "foo3.py",
|
|
1143
|
+
]:
|
|
1144
|
+
with open(path, "w") as f:
|
|
1145
|
+
f.write(txt)
|
|
1146
|
+
|
|
1147
|
+
child = pexpect.spawn(
|
|
1148
|
+
python,
|
|
1149
|
+
[
|
|
1150
|
+
BIN_DIR + "/tidy-imports",
|
|
1151
|
+
"./",
|
|
1152
|
+
"--exclude",
|
|
1153
|
+
"foo.py",
|
|
1154
|
+
"--exclude",
|
|
1155
|
+
"bar/*.py",
|
|
1156
|
+
],
|
|
1157
|
+
timeout=5.0,
|
|
1158
|
+
cwd=tmp_path,
|
|
1159
|
+
logfile=BytesIO(),
|
|
1160
|
+
)
|
|
1161
|
+
child.expect_exact("baz/foo3.py? [y/N]")
|
|
1162
|
+
child.send("y\n")
|
|
1163
|
+
child.expect_exact("what.py? [y/N]")
|
|
1164
|
+
child.send("y\n")
|
|
1165
|
+
child.expect(pexpect.EOF)
|
|
1166
|
+
|
|
1167
|
+
# Check that the tidy-imports output has log messages about exclusion patterns
|
|
1168
|
+
output = child.logfile.getvalue().decode()
|
|
1169
|
+
assert "bar/foo2.py matches exclusion pattern: bar/*.py" in output
|
|
1170
|
+
assert "foo.py matches exclusion pattern: foo.py" in output
|
|
1171
|
+
|
|
1172
|
+
# Check that the two modified files have imports
|
|
1173
|
+
with open(tmp_path / "baz" / "foo3.py") as f:
|
|
1174
|
+
foo3 = f.read()
|
|
1175
|
+
|
|
1176
|
+
with open(tmp_path / "what.py") as f:
|
|
1177
|
+
what = f.read()
|
|
1178
|
+
|
|
1179
|
+
expected = dedent(
|
|
1180
|
+
"""
|
|
1181
|
+
# hello
|
|
1182
|
+
import os
|
|
1183
|
+
import sys
|
|
1184
|
+
|
|
1185
|
+
def foo():
|
|
1186
|
+
foo() + os + sys
|
|
1187
|
+
"""
|
|
1188
|
+
)
|
|
1189
|
+
assert foo3 == expected
|
|
1190
|
+
assert what == expected
|
|
1191
|
+
|
|
1192
|
+
# Check that the two unmodified files don't have imports
|
|
1193
|
+
with open(tmp_path / "foo.py") as f:
|
|
1194
|
+
foo = f.read()
|
|
1195
|
+
|
|
1196
|
+
with open(tmp_path / "bar" / "foo2.py") as f:
|
|
1197
|
+
foo2 = f.read()
|
|
1198
|
+
|
|
1199
|
+
assert foo == txt
|
|
1200
|
+
assert foo2 == txt
|
|
@@ -13,9 +13,11 @@ from pyflyby._log import logger
|
|
|
13
13
|
from pyflyby._modules import (ModuleHandle, _fast_iter_modules,
|
|
14
14
|
_iter_file_finder_modules)
|
|
15
15
|
import re
|
|
16
|
+
import os
|
|
16
17
|
import subprocess
|
|
17
18
|
import sys
|
|
18
19
|
from textwrap import dedent
|
|
20
|
+
from tempfile import TemporaryDirectory
|
|
19
21
|
from unittest import mock
|
|
20
22
|
|
|
21
23
|
import pytest
|
|
@@ -122,7 +124,7 @@ def test_fast_iter_modules():
|
|
|
122
124
|
|
|
123
125
|
assert fast == slow
|
|
124
126
|
|
|
125
|
-
|
|
127
|
+
@mock.patch.dict(os.environ, {"PYFLYBY_SUPPRESS_CACHE_REBUILD_LOGS": "0"})
|
|
126
128
|
@mock.patch("platformdirs.user_cache_dir")
|
|
127
129
|
def test_import_cache(mock_user_cache_dir, tmp_path):
|
|
128
130
|
"""Test that the import cache is built when iterating modules.
|
|
@@ -195,3 +197,20 @@ def test_import_cache(mock_user_cache_dir, tmp_path):
|
|
|
195
197
|
assert len(mock_logger.info.call_args_list) == 1
|
|
196
198
|
assert len(list(tmp_path.iterdir())) == n_cached_paths
|
|
197
199
|
mock_iffm.assert_called_once()
|
|
200
|
+
|
|
201
|
+
@mock.patch.dict(os.environ, {"PYFLYBY_DISABLE_CACHE": "1"})
|
|
202
|
+
@mock.patch("platformdirs.user_cache_dir")
|
|
203
|
+
def test_import_perms(mock_user_cache_dir, tmp_path):
|
|
204
|
+
"""Test that the import cache does not fail on unreadable paths."""
|
|
205
|
+
|
|
206
|
+
mock_user_cache_dir.return_value = tmp_path
|
|
207
|
+
|
|
208
|
+
with TemporaryDirectory(suffix="_pyflyby_restricted") as restricted:
|
|
209
|
+
try:
|
|
210
|
+
os.chmod(restricted, 0o000)
|
|
211
|
+
|
|
212
|
+
sys.path.append(restricted)
|
|
213
|
+
|
|
214
|
+
list(_fast_iter_modules())
|
|
215
|
+
finally:
|
|
216
|
+
sys.path.remove(restricted)
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|