isort-6.0.1/.codecov.yml0000644000000000000000000000022213615410400012015 0ustar00coverage: status: project: yes patch: yes changes: yes comment: layout: "header, diff" behavior: default require_changes: no isort-6.0.1/.cruft.json0000644000000000000000000000103713615410400011673 0ustar00{ "template": "https://github.com/timothycrosley/cookiecutter-python/", "commit": "71391fd9999067ef4b38aa05e7116087fac431f8", "context": { "cookiecutter": { "full_name": "Timothy Crosley", "email": "timothy.crosley@gmail.com", "github_username": "pycqa", "project_name": "isort", "description": "A Python utility / library to sort Python imports.", "version": "4.3.21", "_template": "https://github.com/timothycrosley/cookiecutter-python/" } }, "directory": "", "checkout": null } isort-6.0.1/.deepsource.toml0000644000000000000000000000035613615410400012713 0ustar00version = 1 test_patterns = ["tests/**"] exclude_patterns = [ "tests/**", "scripts/**", "isort/_vendored/**", ] [[analyzers]] name = "python" enabled = true [analyzers.meta] runtime_version = "3.x.x" max_line_length = 100 isort-6.0.1/.dockerignore0000644000000000000000000000035613615410400012256 0ustar00# project build medadata that can't be used in docker Dockerfile .appveyor.yml .dockerignore .pre-commit-hooks.yaml .travis.yml .git* # documentation not needed CHANGELOG.md LICENSE MANIFEST.in .undertake example.gif logo.png art/ docs/ isort-6.0.1/.editorconfig0000644000000000000000000000046113615410400012254 0ustar00root = true [*.py] max_line_length = 100 indent_style = space indent_size = 4 known_first_party = isort known_third_party = kate ignore_frosted_errors = E103 skip = build,.tox,venv balanced_wrapping = true [*.{rst,ini}] indent_style = space indent_size = 4 [*.yml] indent_style = space indent_size = 2 isort-6.0.1/.pre-commit-config.yaml0000644000000000000000000000013513615410400014056 0ustar00repos: - repo: https://github.com/pycqa/isort rev: 5.13.2 hooks: - id: isort isort-6.0.1/.pre-commit-hooks.yaml0000644000000000000000000000040313615410400013732 0ustar00- id: isort name: isort entry: isort stages: [pre-commit, pre-merge-commit, pre-push, manual] require_serial: true language: python types_or: [cython, pyi, python] args: ['--filter-files'] minimum_pre_commit_version: '3.2.0' isort-6.0.1/.pymon0000644000000000000000000034000013615410400010736 0ustar00SQLite format 3@ XX.[4   d11]tableEXECUTION_CONTEXTSEXECUTION_CONTEXTSCREATE TABLE EXECUTION_CONTEXTS ( ENV_H varchar(64) primary key not null unique, CPU_COUNT integer, CPU_FREQUENCY_MHZ integer, CPU_TYPE varchar(64), CPU_VENDOR varchar(256), RAM_TOTAL_MB integer, MACHINE_NODE varchar(512), MACHINE_TYPE varchar(32), MACHINE_ARCH varchar(16), SYSTEM_INFO varchar(256), PYTHON_INFO varchar(512) )CW1indexsqlite_autoindex_EXECUTION_CONTEXTS_1EXECUTION_CONTEXTS %%[tableTEST_METRICSTEST_METRICSCREATE TABLE TEST_METRICS ( SESSION_H varchar(64), -- Session identifier ENV_H varchar(64), -- Environment description identifier ITEM_START_TIME varchar(64), -- Effective start time of the test ITEM_PATH varchar(4096), -- Path of the item, following Python import specification ITEM varchar(2048), -- Name of the item ITEM_VARIANT varchar(2048), -- Optional parametrization of an item. ITEM_FS_LOC varchar(2048), -- Relative path from pytest invocation directory to the item's module. KIND varchar(64), -- Package, Module or function COMPONENT varchar(512) NULL, -- Tested component if any TOTAL_TIME float, -- Total time spent running the item USER_TIME float, -- time spent in user space KERNEL_TIME float, -- time spent in kernel space CPU_USAGE float, -- cpu usage MEM_USAGE float, -- Max resident memory used. FOREIGN KEY (ENV_H) REFERENCES EXECUTION_CONTEXTS(ENV_H), FOREIGN KEY (SESSION_H) REFERENCES TEST_SESSIONS(SESSION_H) )''CtableTEST_SESSIONSTEST_SESSIONSCREATE TABLE TEST_SESSIONS( SESSION_H varchar(64) primary key not null unique, -- Session identifier RUN_DATE varchar(64), -- Date of test run SCM_ID varchar(128), -- SCM change id RUN_DESCRIPTION json )9M'indexsqlite_autoindex_TEST_SESSIONS_1TEST_SESSIONS *iMA]6cb049a30141e2c4629a62ef9e79637e2023-01-23T10:30:20.12476207a516cbdc8b7e164d039ce8d610de2cb19541cd{}iMA]6f0b4a89ef0b6381ba6056099c6dae232023-01-23T10:13:42.18538507a516cbdc8b7e164d039ce8d610de2cb19541cd{}iMA]3674b6304d855296ba650ecd2b7b6f5b2023-01-23T10:12:54.17709107a516cbdc8b7e164d039ce8d610de2cb19541cd{} $M6cb049a30141e2c4629a62ef9e79637e$M6f0b4a89ef0b6381ba6056099c6dae23#M 3674b6304d855296ba650ecd2b7b6f5bxMMA?%%i 6f0b4a89ef0b6381ba6056099c6dae233b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:19:16.961303test_projects_using_isorttest_pyramidtest_pyramidtests\integration\test_projects_using_isort.pyfunction@,~H???QDq@]MMA?IIi 6f0b4a89ef0b6381ba6056099c6dae233b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:17:48.927133test_projects_using_isorttest_datadog_integrations_coretest_datadog_integrations_coretests\integration\test_projects_using_isort.pyfunction@Vz@@?E4a` @]]t MMA?!!i 6f0b4a89ef0b6381ba6056099c6dae233b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:17:45.487538test_projects_using_isorttest_attrstest_attrstests\integration\test_projects_using_isort.pyfunction@ f'???s@]O@v MMA?##i 6f0b4a89ef0b6381ba6056099c6dae233b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:17:24.962663test_projects_using_isorttest_pillowtest_pillowtests\integration\test_projects_using_isort.pyfunction@48???HrF@]O@~ MMA?++i 6f0b4a89ef0b6381ba6056099c6dae233b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:17:16.761721test_projects_using_isorttest_hypothesistest_hypothesistests\integration\test_projects_using_isort.pyfunction@ _2???]0v@]O@v MMA?##i 6f0b4a89ef0b6381ba6056099c6dae233b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:17:10.392109test_projects_using_isorttest_poetrytest_poetrytests\integration\test_projects_using_isort.pyfunction@n|@???% ,@]O@v MMA?##i 6f0b4a89ef0b6381ba6056099c6dae233b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:16:54.788313test_projects_using_isorttest_pylinttest_pylinttests\integration\test_projects_using_isort.pyfunction@//uh???6j0@]O@zMMA?''i 6f0b4a89ef0b6381ba6056099c6dae233b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:16:15.067110test_projects_using_isorttest_typeshedtest_typeshedtests\integration\test_projects_using_isort.pyfunction@Cڈ?@?@?#O.@]O@~MMA?++i 6f0b4a89ef0b6381ba6056099c6dae233b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:16:05.892945test_projects_using_isorttest_websocketstest_websocketstests\integration\test_projects_using_isort.pyfunction@"x???6~u@]OMMA?--i 6f0b4a89ef0b6381ba6056099c6dae233b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:15:46.442546test_projects_using_isorttest_habitat_labtest_habitat_labtests\integration\test_projects_using_isort.pyfunction@'e9`???Ƒ@]JpMMA?%%i 6f0b4a89ef0b6381ba6056099c6dae233b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:15:41.393270test_projects_using_isorttest_fastapitest_fastapitests\integration\test_projects_using_isort.pyfunction@%zp??<}%@]JvMMA?##i 6f0b4a89ef0b6381ba6056099c6dae233b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:15:15.675188test_projects_using_isorttest_pandastest_pandastests\integration\test_projects_using_isort.pyfunction@9~???@fJW@]lMMA?!!i 6f0b4a89ef0b6381ba6056099c6dae233b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:15:12.265005test_projects_using_isorttest_plonetest_plonetests\integration\test_projects_using_isort.pyfunction@ +`??D]:@]|vMMA?##i 6f0b4a89ef0b6381ba6056099c6dae233b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:13:59.534252test_projects_using_isorttest_djangotest_djangotests\integration\test_projects_using_isort.pyfunction@R-"@@?Sיz@]MMA/==Y 6f0b4a89ef0b6381ba6056099c6dae233b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:13:46.494872test_hypothesmithtest_isort_is_iK;,rcSB2# q ` O ? / } Mss+% 3b6dbb3ba9adaac90d99a9df3396d5a1Intel64 Family 6 Model 126 Stepping 5, GenuineIntelIntel64 Family 6 Model 126 Stepping 5, GenuineIntel>aMARK-TEREM.HomeAMD6464bitWindows - 103.11.0 (main, Oct 24 2022, 18:26:48) [MSC v.1933 64 bit (AMD64)] #M 3b6dbb3ba9adaac90d99a9df3396d5a1 +   ) & %(/65<E&+xMMA?%%i 6f0b4a89ef0b6381ba6056099c6dae233b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:19:16.961303test_projects_using_isorttest_pyramidtest_pyramidtests\integration\test_projects_using_isort.pyfunction@,~H???QDq@]MMA?IIi 6f0b4a89ef0b6381ba6056099c6dae233b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:17:48.927133test_projects_using_isorttest_datadog_integrations_coretest_datadog_integrations_coretests\integration\test_projects_using_isort.pyfunction@Vz@@?E4a` @]]t MMA?!!i 6f0b4a89ef0b6381ba6056099c6dae233b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:17:45.487538test_projects_using_isorttest_attrstest_attrstests\integration\test_projects_using_isort.pyfunction@ f'???s@]O@v MMA?##i 6f0b4a89ef0b6381ba6056099c6dae233b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:17:24.962663test_projects_using_isorttest_pillowtest_pillowtests\integration\test_projects_using_isort.pyfunction@48???HrF@]O@~ MMA?++i 6f0b4a89ef0b6381ba6056099c6dae233b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:17:16.761721test_projects_using_isorttest_hypothesistest_hypothesistests\integration\test_projects_using_isort.pyfunction@ _2???]0v@]O@v MMA?##i 6f0b4a89ef0b6381ba6056099c6dae233b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:17:10.392109test_projects_using_isorttest_poetrytest_poetrytests\integration\test_projects_using_isort.pyfunction@n|@???% ,@]O@v MMA?##i 6f0b4a89ef0b6381ba6056099c6dae233b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:16:54.788313test_projects_using_isorttest_pylinttest_pylinttests\integration\test_projects_using_isort.pyfunction@//uh???6j0@]O@zMMA?''i 6f0b4a89ef0b6381ba6056099c6dae233b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:16:15.067110test_projects_using_isorttest_typeshedtest_typeshedtests\integration\test_projects_using_isort.pyfunction@Cڈ?@?@?#O.@]O@~MMA?++i 6f0b4a89ef0b6381ba6056099c6dae233b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:16:05.892945test_projects_using_isorttest_websocketstest_websocketstests\integration\test_projects_using_isort.pyfunction@"x???6~u@]OMMA?--i 6f0b4a89ef0b6381ba6056099c6dae233b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:15:46.442546test_projects_using_isorttest_habitat_labtest_habitat_labtests\integration\test_projects_using_isort.pyfunction@'e9`???Ƒ@]JpMMA?%%i 6f0b4a89ef0b6381ba6056099c6dae233b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:15:41.393270test_projects_using_isorttest_fastapitest_fastapitests\integration\test_projects_using_isort.pyfunction@%zp??<}%@]JvMMA?##i 6f0b4a89ef0b6381ba6056099c6dae233b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:15:15.675188test_projects_using_isorttest_pandastest_pandastests\integration\test_projects_using_isort.pyfunction@9~???@fJW@]lMMA?!!i 6f0b4a89ef0b6381ba6056099c6dae233b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:15:12.265005test_projects_using_isorttest_plonetest_plonetests\integration\test_projects_using_isort.pyfunction@ +`??D]:@]|vMMA?##i 6f0b4a89ef0b6381ba6056099c6dae233b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:13:59.534252test_projects_using_isorttest_djangotest_djangotests\integration\test_projects_using_isort.pyfunction@R-"@@?Sיz@]MMA/==Y 6f0b4a89ef0b6381ba6056099c6dae233b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:13:46.494872test_hypothesmithtest_isort_is_idempotenttest_isort_is_idempotenttests\integration\test_hypothesmith.pyfunction@* @@ ??F~@_( t   4 I\Y`ipurqtzMMA?''i 6cb049a30141e2c4629a62ef9e79637e3b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:32:46.664713test_projects_using_isorttest_typeshedtest_typeshedtests\integration\test_projects_using_isort.pyfunction@Di"??@?;_@`~MMA?++i 6cb049a30141e2c4629a62ef9e79637e3b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:32:42.240379test_projects_using_isorttest_websocketstest_websocketstests\integration\test_projects_using_isort.pyfunction@'???7 a@`MMA?--i 6cb049a30141e2c4629a62ef9e79637e3b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:32:25.695294test_projects_using_isorttest_habitat_labtest_habitat_labtests\integration\test_projects_using_isort.pyfunction@":???M@`@xMMA?%%i 6cb049a30141e2c4629a62ef9e79637e3b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:32:19.342642test_projects_using_isorttest_fastapitest_fastapitests\integration\test_projects_using_isort.pyfunction@@`???Wd@`@vMMA?##i 6cb049a30141e2c4629a62ef9e79637e3b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:31:54.127688test_projects_using_isorttest_pandastest_pandastests\integration\test_projects_using_isort.pyfunction@93y???%@`@tMMA?!!i 6cb049a30141e2c4629a62ef9e79637e3b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:31:50.719542test_projects_using_isorttest_plonetest_plonetests\integration\test_projects_using_isort.pyfunction@ &???#}@`vMMA?##i 6cb049a30141e2c4629a62ef9e79637e3b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:30:50.095192test_projects_using_isorttest_djangotest_djangotests\integration\test_projects_using_isort.pyfunction@NN3"@@??>?@`MMA/==Y 6cb049a30141e2c4629a62ef9e79637e3b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:30:24.172969test_hypothesmithtest_isort_is_idempotenttest_isort_is_idempotenttests\integration\test_hypothesmith.pyfunction@9I@??Tqz@cjMMA3==9 6f0b4a89ef0b6381ba6056099c6dae233b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:20:29.759652tests.unit.test_apitest_sort_file_to_stdouttest_sort_file_to_stdouttests\unit\test_api.pyfunction???ڄn@_hMMA3;;9 6f0b4a89ef0b6381ba6056099c6dae233b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:20:28.677205tests.unit.test_apitest_sort_file_in_placetest_sort_file_in_placetests\unit\test_api.pyfunction?r??Ɔ2: @_VMMA3))9 6f0b4a89ef0b6381ba6056099c6dae233b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:20:27.483908tests.unit.test_apitest_sort_filetest_sort_filetests\unit\test_api.pyfunction?a@??Y;Z@_vMMA3II9 6f0b4a89ef0b6381ba6056099c6dae233b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:20:26.400577tests.unit.test_apitest_sort_file_with_bad_syntaxtest_sort_file_with_bad_syntaxtests\unit\test_api.pyfunction?@??ѫ@_|MMAK77Q 6f0b4a89ef0b6381ba6056099c6dae233b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:20:25.233344tests.unit.test_action_commentstest_isort_off_and_ontest_isort_off_and_ontests\unit\test_action_comments.pyfunction?cH??g0x@_rMMA?i 6f0b4a89ef0b6381ba6056099c6dae233b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:19:38.573303test_projects_using_isorttest_zopetest_zopetests\integration\test_projects_using_isort.pyfunction@7V@???J't@]tMMA?!!i 6f0b4a89ef0b6381ba6056099c6dae233b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:19:34.655744test_projects_using_isorttest_dobbytest_dobbytests\integration\test_projects_using_isort.pyfunction@$???횚@] MMA?99i 6f0b4a89ef0b6381ba6056099c6dae233b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:19:31.233335test_projects_using_isorttest_products_zopetreetest_products_zopetreetests\integration\test_projects_using_isort.pyfunction@ 4$`???+h9@] t    ?T_th/MMA3;;9 6cb049a30141e2c4629a62ef9e79637e3b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:36:12.814122tests.unit.test_apitest_other_ask_to_applytest_other_ask_to_applytests\unit\test_api.pyfunction???$-l)@`r.MMA3==9 6cb049a30141e2c4629a62ef9e79637e3b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:36:11.627890tests.unit.test_apitest_sort_file_to_stdouttest_sort_file_to_stdouttests\unit\test_api.pyfunction?C???XT[5@``h-MMA3;;9 6cb049a30141e2c4629a62ef9e79637e3b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:36:10.424880tests.unit.test_apitest_sort_file_in_placetest_sort_file_in_placetests\unit\test_api.pyfunction? ???|o@``V,MMA3))9 6cb049a30141e2c4629a62ef9e79637e3b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:36:09.174802tests.unit.test_apitest_sort_filetest_sort_filetests\unit\test_api.pyfunction???*=}@``v+MMA3II9 6cb049a30141e2c4629a62ef9e79637e3b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:36:07.897000tests.unit.test_apitest_sort_file_with_bad_syntaxtest_sort_file_with_bad_syntaxtests\unit\test_api.pyfunction?4y@??(4@``*MMAK77Q 6cb049a30141e2c4629a62ef9e79637e3b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:36:06.789848tests.unit.test_action_commentstest_isort_off_and_ontest_isort_off_and_ontests\unit\test_action_comments.pyfunction?@???C2:@``r)MMA?i 6cb049a30141e2c4629a62ef9e79637e3b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:35:48.361944test_projects_using_isorttest_zopetest_zopetests\integration\test_projects_using_isort.pyfunction@)???hƩ>@``t(MMA?!!i 6cb049a30141e2c4629a62ef9e79637e3b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:35:45.820508test_projects_using_isorttest_dobbytest_dobbytests\integration\test_projects_using_isort.pyfunction@6???UKv@``'MMA?99i 6cb049a30141e2c4629a62ef9e79637e3b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:35:43.033051test_projects_using_isorttest_products_zopetreetest_products_zopetreetests\integration\test_projects_using_isort.pyfunction@,??4ռU@``p&MMA?%%i 6cb049a30141e2c4629a62ef9e79637e3b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:35:35.382129test_projects_using_isorttest_pyramidtest_pyramidtests\integration\test_projects_using_isort.pyfunction@A`??at@``%MMA?IIi 6cb049a30141e2c4629a62ef9e79637e3b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:34:21.979346test_projects_using_isorttest_datadog_integrations_coretest_datadog_integrations_coretests\integration\test_projects_using_isort.pyfunction@RXO???8m@a t$MMA?!!i 6cb049a30141e2c4629a62ef9e79637e3b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:34:18.340598test_projects_using_isorttest_attrstest_attrstests\integration\test_projects_using_isort.pyfunction@ ???K'@`v#MMA?##i 6cb049a30141e2c4629a62ef9e79637e3b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:33:59.111461test_projects_using_isorttest_pillowtest_pillowtests\integration\test_projects_using_isort.pyfunction@36,???&Ü1'@`~"MMA?++i 6cb049a30141e2c4629a62ef9e79637e3b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:33:51.294725test_projects_using_isorttest_hypothesistest_hypothesistests\integration\test_projects_using_isort.pyfunction@40???{J@`v!MMA?##i 6cb049a30141e2c4629a62ef9e79637e3b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:33:44.429947test_projects_using_isorttest_poetrytest_poetrytests\integration\test_projects_using_isort.pyfunction@g???1XP@`v MMA?##i 6cb049a30141e2c4629a62ef9e79637e3b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:33:27.502669test_projects_using_isorttest_pylinttest_pylinttests\integration\test_projects_using_isort.pyfunction@0???5A@`   8 3 D Unun?MMAQ##W 6cb049a30141e2c4629a62ef9e79637e3b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:36:31.601997tests.unit.test_deprecated_finderstest_createtest_createtests\unit\test_deprecated_finders.pyfunction???؍\@`j>MMAQW 6cb049a30141e2c4629a62ef9e79637e3b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:36:30.475671tests.unit.test_deprecated_finderstest_findtest_findtests\unit\test_deprecated_finders.pyfunction?-??ńe@`n=MMAQ##W 6cb049a30141e2c4629a62ef9e79637e3b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:36:29.290208tests.unit.test_deprecated_finderstest_createtest_createtests\unit\test_deprecated_finders.pyfunction?Ʊ?? @`<MMAQ;;W 6cb049a30141e2c4629a62ef9e79637e3b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:36:28.043253tests.unit.test_deprecated_finderstest_find_broken_findertest_find_broken_findertests\unit\test_deprecated_finders.pyfunction???䠂@`v;MMAQ++W 6cb049a30141e2c4629a62ef9e79637e3b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:36:26.978670tests.unit.test_deprecated_finderstest_no_finderstest_no_finderstests\unit\test_deprecated_finders.pyfunction?Z@???ΐ@`j:MMAQW 6cb049a30141e2c4629a62ef9e79637e3b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:36:25.898843tests.unit.test_deprecated_finderstest_inittest_inittests\unit\test_deprecated_finders.pyfunction???tf@`b9MMA=++C 6cb049a30141e2c4629a62ef9e79637e3b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:36:24.587238tests.unit.test_commentstest_fuzz_parsetest_fuzz_parsetests\unit\test_comments.pyfunction?G??ŇG@`v8MMA=77C 6cb049a30141e2c4629a62ef9e79637e3b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:36:22.899049tests.unit.test_commentstest_fuzz_add_to_linetest_fuzz_add_to_linetests\unit\test_comments.pyfunction????G#@`d7MMA=--C 6cb049a30141e2c4629a62ef9e79637e3b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:36:21.834496tests.unit.test_commentstest_add_to_linetest_add_to_linetests\unit\test_comments.pyfunction?u??"@`l6MMA3??9 6cb049a30141e2c4629a62ef9e79637e3b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:36:20.742904tests.unit.test_apitest_find_imports_in_codetest_find_imports_in_codetests\unit\test_api.pyfunction?E@??` c@`l5MMA3??9 6cb049a30141e2c4629a62ef9e79637e3b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:36:19.601893tests.unit.test_apitest_find_imports_in_filetest_find_imports_in_filetests\unit\test_api.pyfunction? 1@??ҽ+@`4MMA3UU9 6cb049a30141e2c4629a62ef9e79637e3b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:36:18.447912tests.unit.test_apitest_sort_code_string_mixed_newlinestest_sort_code_string_mixed_newlinestests\unit\test_api.pyfunction?1I??$~A@`Z3MMA3--9 6cb049a30141e2c4629a62ef9e79637e3b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:36:17.334288tests.unit.test_apitest_diff_streamtest_diff_streamtests\unit\test_api.pyfunction???,q>Mk@`2MMA3UU9 6cb049a30141e2c4629a62ef9e79637e3b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:36:16.248561tests.unit.test_apitest_sorted_imports_multiple_configstest_sorted_imports_multiple_configstests\unit\test_api.pyfunction?2??f@`r1MMA3EE9 6cb049a30141e2c4629a62ef9e79637e3b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:36:15.173391tests.unit.test_apitest_check_file_with_changestest_check_file_with_changestests\unit\test_api.pyfunction?@??\@`n0MMA3AA9 6cb049a30141e2c4629a62ef9e79637e3b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:36:14.084930tests.unit.test_apitest_check_file_no_changestest_check_file_no_changestests\unit\test_api.pyfunction?- @??[>io@` " 5 D W f qb_hwxOMMAQ--W 6cb049a30141e2c4629a62ef9e79637e3b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:36:49.174296tests.unit.test_deprecated_finderstest_not_enabledtest_not_enabledtests\unit\test_deprecated_finders.pyfunction???Ώy@` vNMMAQ++W 6cb049a30141e2c4629a62ef9e79637e3b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:36:48.160440tests.unit.test_deprecated_finderstest_no_pipreqstest_no_pipreqstests\unit\test_deprecated_finders.pyfunction?Q??2]q@` jMMMAQW 6cb049a30141e2c4629a62ef9e79637e3b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:36:47.224992tests.unit.test_deprecated_finderstest_findtest_findtests\unit\test_deprecated_finders.pyfunction?픃??xm@` nLMMAQ##W 6cb049a30141e2c4629a62ef9e79637e3b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:36:46.322025tests.unit.test_deprecated_finderstest_createtest_createtests\unit\test_deprecated_finders.pyfunction?o??t:@` jKMMAQW 6cb049a30141e2c4629a62ef9e79637e3b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:36:45.302205tests.unit.test_deprecated_finderstest_findtest_findtests\unit\test_deprecated_finders.pyfunction?@??>:3@` nJMMAQ##W 6cb049a30141e2c4629a62ef9e79637e3b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:36:44.222093tests.unit.test_deprecated_finderstest_createtest_createtests\unit\test_deprecated_finders.pyfunction?h@??Ԗz +e@` tIMMAQ))W 6cb049a30141e2c4629a62ef9e79637e3b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:36:43.020695tests.unit.test_deprecated_finderstest_src_pathstest_src_pathstests\unit\test_deprecated_finders.pyfunction???ۏ6ڶ@` HMMAQ55W 6cb049a30141e2c4629a62ef9e79637e3b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:36:41.863868tests.unit.test_deprecated_finderstest_default_sectiontest_default_sectiontests\unit\test_deprecated_finders.pyfunction?M\??z[ 2 .@` GMMAQAAW 6cb049a30141e2c4629a62ef9e79637e3b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:36:40.692595tests.unit.test_deprecated_finderstest_conda_and_virtual_envtest_conda_and_virtual_envtests\unit\test_deprecated_finders.pyfunction???E@` rFMMAQW 6cb049a30141e2c4629a62ef9e79637e3b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:36:39.508259tests.unit.test_deprecated_finderstest_findtest_findtests\unit\test_deprecated_finders.pyfunction?@???[C@`nEMMAQ##W 6cb049a30141e2c4629a62ef9e79637e3b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:36:38.299239tests.unit.test_deprecated_finderstest_createtest_createtests\unit\test_deprecated_finders.pyfunction???n`K@`jDMMAQW 6cb049a30141e2c4629a62ef9e79637e3b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:36:37.228473tests.unit.test_deprecated_finderstest_findtest_findtests\unit\test_deprecated_finders.pyfunction?y??p.t@`nCMMAQ##W 6cb049a30141e2c4629a62ef9e79637e3b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:36:36.129853tests.unit.test_deprecated_finderstest_createtest_createtests\unit\test_deprecated_finders.pyfunction?f??Og@`jBMMAQW 6cb049a30141e2c4629a62ef9e79637e3b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:36:35.024220tests.unit.test_deprecated_finderstest_findtest_findtests\unit\test_deprecated_finders.pyfunction???B8P(@`nAMMAQ##W 6cb049a30141e2c4629a62ef9e79637e3b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:36:33.911086tests.unit.test_deprecated_finderstest_createtest_createtests\unit\test_deprecated_finders.pyfunction? ??' @`j@MMAQW 6cb049a30141e2c4629a62ef9e79637e3b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:36:32.713645tests.unit.test_deprecated_finderstest_findtest_findtests\unit\test_deprecated_finders.pyfunction?N@??kLP@` ( ? Z q 0Sjf`MMAA++G 6cb049a30141e2c4629a62ef9e79637e3b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:37:07.950025tests.unit.test_exceptionstest_pickleabletest_pickleabletests\unit\test_exceptions.pyfunction?|p??K68j@`Z_MMAAG 6cb049a30141e2c4629a62ef9e79637e3b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:37:07.039325tests.unit.test_exceptionstest_inittest_inittests\unit\test_exceptions.pyfunction???C}*G@`d^MMAA))G 6cb049a30141e2c4629a62ef9e79637e3b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:37:06.153929tests.unit.test_exceptionstest_variablestest_variablestests\unit\test_exceptions.pyfunction?W??ĦJxQ@`f]MMAA++G 6cb049a30141e2c4629a62ef9e79637e3b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:37:05.242946tests.unit.test_exceptionstest_pickleabletest_pickleabletests\unit\test_exceptions.pyfunction?̬??0@`Z\MMAAG 6cb049a30141e2c4629a62ef9e79637e3b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:37:04.270878tests.unit.test_exceptionstest_inittest_inittests\unit\test_exceptions.pyfunction???6:@`d[MMAA))G 6cb049a30141e2c4629a62ef9e79637e3b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:37:03.278017tests.unit.test_exceptionstest_variablestest_variablestests\unit\test_exceptions.pyfunction?ov??nY𞧞@`fZMMAA++G 6cb049a30141e2c4629a62ef9e79637e3b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:37:02.341711tests.unit.test_exceptionstest_pickleabletest_pickleabletests\unit\test_exceptions.pyfunction?펣??|8@`ZYMMAAG 6cb049a30141e2c4629a62ef9e79637e3b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:37:01.393984tests.unit.test_exceptionstest_inittest_inittests\unit\test_exceptions.pyfunction?敀??C/@`dXMMAA))G 6cb049a30141e2c4629a62ef9e79637e3b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:37:00.443693tests.unit.test_exceptionstest_variablestest_variablestests\unit\test_exceptions.pyfunction???1]6@`fWMMAA++G 6cb049a30141e2c4629a62ef9e79637e3b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:36:59.450605tests.unit.test_exceptionstest_pickleabletest_pickleabletests\unit\test_exceptions.pyfunction?]??]!MV@`ZVMMAAG 6cb049a30141e2c4629a62ef9e79637e3b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:36:58.512183tests.unit.test_exceptionstest_inittest_inittests\unit\test_exceptions.pyfunction?v??@H@`dUMMAA))G 6cb049a30141e2c4629a62ef9e79637e3b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:36:57.524625tests.unit.test_exceptionstest_variablestest_variablestests\unit\test_exceptions.pyfunction?/??xG= D@`fTMMAA++G 6cb049a30141e2c4629a62ef9e79637e3b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:36:56.587808tests.unit.test_exceptionstest_pickleabletest_pickleabletests\unit\test_exceptions.pyfunction?wO??`@`djMMAA))G 6cb049a30141e2c4629a62ef9e79637e3b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:37:17.817467tests.unit.test_exceptionstest_variablestest_variablestests\unit\test_exceptions.pyfunction???t*jA@`fiMMAA++G 6cb049a30141e2c4629a62ef9e79637e3b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:37:16.902690tests.unit.test_exceptionstest_pickleabletest_pickleabletests\unit\test_exceptions.pyfunction?ɾ??N@`ZhMMAAG 6cb049a30141e2c4629a62ef9e79637e3b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:37:15.876598tests.unit.test_exceptionstest_inittest_inittests\unit\test_exceptions.pyfunction?0??EUe@`dgMMAA))G 6cb049a30141e2c4629a62ef9e79637e3b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:37:14.699637tests.unit.test_exceptionstest_variablestest_variablestests\unit\test_exceptions.pyfunction?@??Ewhy@`ffMMAA++G 6cb049a30141e2c4629a62ef9e79637e3b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:37:13.725391tests.unit.test_exceptionstest_pickleabletest_pickleabletests\unit\test_exceptions.pyfunction???r]@`ZeMMAAG 6cb049a30141e2c4629a62ef9e79637e3b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:37:12.694546tests.unit.test_exceptionstest_inittest_inittests\unit\test_exceptions.pyfunction?G1??p즼@`ddMMAA))G 6cb049a30141e2c4629a62ef9e79637e3b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:37:11.784435tests.unit.test_exceptionstest_variablestest_variablestests\unit\test_exceptions.pyfunction?Ӏ??`@`fcMMAA++G 6cb049a30141e2c4629a62ef9e79637e3b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:37:10.872530tests.unit.test_exceptionstest_pickleabletest_pickleabletests\unit\test_exceptions.pyfunction?엚??%5_@`ZbMMAAG 6cb049a30141e2c4629a62ef9e79637e3b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:37:09.899265tests.unit.test_exceptionstest_inittest_inittests\unit\test_exceptions.pyfunction?2??H@`daMMAA))G 6cb049a30141e2c4629a62ef9e79637e3b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:37:08.947884tests.unit.test_exceptionstest_variablestest_variablestests\unit\test_exceptions.pyfunction???)}z!+@` 0 S j XMMA7''= 6cb049a30141e2c4629a62ef9e79637e3b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:37:41.666197tests.unit.test_hookstest_git_hooktest_git_hooktests\unit\test_hooks.pyfunction?þ??6E@`vMMA9CC? 6cb049a30141e2c4629a62ef9e79637e3b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:37:40.143809tests.unit.test_formattest_fuzz_show_unified_difftest_fuzz_show_unified_difftests\unit\test_format.pyfunction?(??v]@`MMA9ii? 6cb049a30141e2c4629a62ef9e79637e3b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:37:38.985681tests.unit.test_formattest_colorama_not_available_handled_gracefullytest_colorama_not_available_handled_gracefullytests\unit\test_format.pyfunction?TV??uP<@`~MMA9MM? 6cb049a30141e2c4629a62ef9e79637e3b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:37:37.767367tests.unit.test_formattest_colored_printer_diff_outputtest_colored_printer_diff_outputtests\unit\test_format.pyfunction?UC??{S@`r}MMA9??? 6cb049a30141e2c4629a62ef9e79637e3b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:37:36.700873tests.unit.test_formattest_colored_printer_difftest_colored_printer_difftests\unit\test_format.pyfunction?@??͑08@`t|MMA9AA? 6cb049a30141e2c4629a62ef9e79637e3b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:37:35.620928tests.unit.test_formattest_colored_printer_errortest_colored_printer_errortests\unit\test_format.pyfunction?d??)@`x{MMA9EE? 6cb049a30141e2c4629a62ef9e79637e3b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:37:34.495735tests.unit.test_formattest_colored_printer_successtest_colored_printer_successtests\unit\test_format.pyfunction?ӷ??T)e-m@`nzMMA9;;? 6cb049a30141e2c4629a62ef9e79637e3b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:37:33.444041tests.unit.test_formattest_basic_printer_difftest_basic_printer_difftests\unit\test_format.pyfunction???7Ǚ@`lyMMA911? 6cb049a30141e2c4629a62ef9e79637e3b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:37:32.464584tests.unit.test_formattest_basic_printertest_basic_printertests\unit\test_format.pyfunction? ???ŒHԈ@`xMMA9__? 6cb049a30141e2c4629a62ef9e79637e3b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:37:31.543812tests.unit.test_formattest_ask_whether_to_apply_changes_to_filetest_ask_whether_to_apply_changes_to_filetests\unit\test_format.pyfunction?$J???%B@`PwMMA7= 6cb049a30141e2c4629a62ef9e79637e3b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:37:30.597450tests.unit.test_filestest_findtest_findtests\unit\test_files.pyfunction?m??=-@`dvMMAA))G 6cb049a30141e2c4629a62ef9e79637e3b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:37:29.608498tests.unit.test_exceptionstest_variablestest_variablestests\unit\test_exceptions.pyfunction?o??ЃQw@`fuMMAA++G 6cb049a30141e2c4629a62ef9e79637e3b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:37:28.632640tests.unit.test_exceptionstest_pickleabletest_pickleabletests\unit\test_exceptions.pyfunction?R??wp@`ZtMMAAG 6cb049a30141e2c4629a62ef9e79637e3b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:37:27.559585tests.unit.test_exceptionstest_inittest_inittests\unit\test_exceptions.pyfunction?߹??^@`dsMMAA))G 6cb049a30141e2c4629a62ef9e79637e3b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:37:26.642344tests.unit.test_exceptionstest_variablestest_variablestests\unit\test_exceptions.pyfunction???JuK@`frMMAA++G 6cb049a30141e2c4629a62ef9e79637e3b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:37:25.678793tests.unit.test_exceptionstest_pickleabletest_pickleabletests\unit\test_exceptions.pyfunction?["??AR@` < *L<^MMA7--= 6cb049a30141e2c4629a62ef9e79637e3b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:38:09.138114tests.unit.test_isorttest_length_sorttest_length_sorttests\unit\test_isort.pyfunction?#@??XD{@`fMMA755= 6cb049a30141e2c4629a62ef9e79637e3b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:38:07.816143tests.unit.test_isorttest_qa_comment_casetest_qa_comment_casetests\unit\test_isort.pyfunction?@??_d)@`hMMA7//= 6cb049a30141e2c4629a62ef9e79637e3b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:38:06.493227tests.unit.test_isorttest_output_modestest_output_modestests\unit\test_isort.pyfunction????i+ŗ@`^MMA7--= 6cb049a30141e2c4629a62ef9e79637e3b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:38:05.287856tests.unit.test_isorttest_line_lengthtest_line_lengthtests\unit\test_isort.pyfunction?@??k>ªg@`dMMA733= 6cb049a30141e2c4629a62ef9e79637e3b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:38:04.051924tests.unit.test_isorttest_sort_on_numbertest_sort_on_numbertests\unit\test_isort.pyfunction?;??iҔr@` MMA7QQ= 6cb049a30141e2c4629a62ef9e79637e3b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:38:02.693105tests.unit.test_isorttest_correct_space_between_importstest_correct_space_between_importstests\unit\test_isort.pyfunction?m?? DR@`f MMA755= 6cb049a30141e2c4629a62ef9e79637e3b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:38:01.535980tests.unit.test_isorttest_code_intermixedtest_code_intermixedtests\unit\test_isort.pyfunction?J>??L~Й@`\ MMA7++= 6cb049a30141e2c4629a62ef9e79637e3b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:38:00.232978tests.unit.test_isorttest_happy_pathtest_happy_pathtests\unit\test_isort.pyfunction???@`: MMA17 6cb049a30141e2c4629a62ef9e79637e3b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:37:57.751009tests.unit.test_iotest_opentest_opentests\unit\test_io.pyfunction@w@`Z MMA1//7 6cb049a30141e2c4629a62ef9e79637e3b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:37:55.670574tests.unit.test_iotest_from_contenttest_from_contenttests\unit\test_io.pyfunction@??v9X@`^MMA=''C 6cb049a30141e2c4629a62ef9e79637e3b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:37:51.992921tests.unit.test_identifytest_indentedtest_indentedtests\unit\test_identify.pyfunction???_͘@`\MMA=%%C 6cb049a30141e2c4629a62ef9e79637e3b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:37:49.894296tests.unit.test_identifytest_aliasestest_aliasestests\unit\test_identify.pyfunction@h??+r(`P@`nMMA=77C 6cb049a30141e2c4629a62ef9e79637e3b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:37:47.983041tests.unit.test_identifytest_complex_examplestest_complex_examplestests\unit\test_identify.pyfunction?3D@??n$7@`MMA=KKC 6cb049a30141e2c4629a62ef9e79637e3b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:37:46.797307tests.unit.test_identifytest_yield_and_raise_edge_casestest_yield_and_raise_edge_casestests\unit\test_identify.pyfunction?h@??U3EK@`jMMA=33C 6cb049a30141e2c4629a62ef9e79637e3b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:37:45.321959tests.unit.test_identifytest_top_doc_stringtest_top_doc_stringtests\unit\test_identify.pyfunction?e@??g@`^MMA=''C 6cb049a30141e2c4629a62ef9e79637e3b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:37:44.054759tests.unit.test_identifytest_top_onlytest_top_onlytests\unit\test_identify.pyfunction?9@?? k@`HMMA7= 6cb049a30141e2c4629a62ef9e79637e3b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:37:42.790496tests.unit.test_hookstest_git_hook_uses_the_configuration_file_specified_in_settings_pathtest_git_hook_uses_the_configuration_file_specified_in_settings_pathtests\unit\test_hooks.pyfunction? ??1X(@` V  0 J ` .2HVn#MMA755= 6cb049a30141e2c4629a62ef9e79637e3b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:38:26.412223tests.unit.test_isorttest_default_sectiontest_default_sectiontests\unit\test_isort.pyfunction????BA@`f"MMA755= 6cb049a30141e2c4629a62ef9e79637e3b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:38:25.482059tests.unit.test_isorttest_forced_separatetest_forced_separatetests\unit\test_isort.pyfunction??Ā??ñc"i@`x!MMA7GG= 6cb049a30141e2c4629a62ef9e79637e3b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:38:24.477324tests.unit.test_isorttest_check_newline_in_importstest_check_newline_in_importstests\unit\test_isort.pyfunction?ﱭ??;Okkx@`d MMA733= 6cb049a30141e2c4629a62ef9e79637e3b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:38:23.470961tests.unit.test_isorttest_quotes_in_filetest_quotes_in_filetests\unit\test_isort.pyfunction?ヤ?? ( j@`vMMA7EE= 6cb049a30141e2c4629a62ef9e79637e3b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:38:22.473204tests.unit.test_isorttest_explicitly_local_importtest_explicitly_local_importtests\unit\test_isort.pyfunction?x??DT@`dMMA733= 6cb049a30141e2c4629a62ef9e79637e3b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:38:21.528696tests.unit.test_isorttest_comments_abovetest_comments_abovetests\unit\test_isort.pyfunction?;?? @`lMMA733= 6cb049a30141e2c4629a62ef9e79637e3b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:38:20.545989tests.unit.test_isorttest_remove_importstest_remove_importstests\unit\test_isort.pyfunction?k???ħQH@`^MMA7--= 6cb049a30141e2c4629a62ef9e79637e3b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:38:19.540443tests.unit.test_isorttest_add_importstest_add_importstests\unit\test_isort.pyfunction?k??C^S@``MMA7//= 6cb049a30141e2c4629a62ef9e79637e3b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:38:18.543568tests.unit.test_isorttest_force_to_toptest_force_to_toptests\unit\test_isort.pyfunction?o??Ij@`hMMA777= 6cb049a30141e2c4629a62ef9e79637e3b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:38:17.555420tests.unit.test_isorttest_skip_within_filetest_skip_within_filetests\unit\test_isort.pyfunction?4E??ud%@`nMMA7=== 6cb049a30141e2c4629a62ef9e79637e3b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:38:16.611362tests.unit.test_isorttest_skip_with_file_nametest_skip_with_file_nametests\unit\test_isort.pyfunction???6w`@`PMMA7= 6cb049a30141e2c4629a62ef9e79637e3b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:38:15.675731tests.unit.test_isorttest_skiptest_skiptests\unit\test_isort.pyfunction?톷??XX۳D@`fMMA755= 6cb049a30141e2c4629a62ef9e79637e3b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:38:14.690872tests.unit.test_isorttest_use_parenthesestest_use_parenthesestests\unit\test_isort.pyfunction?帀??Cπ@`bMMA711= 6cb049a30141e2c4629a62ef9e79637e3b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:38:13.735461tests.unit.test_isorttest_custom_indenttest_custom_indenttests\unit\test_isort.pyfunction?z??́^Ka @`fMMA755= 6cb049a30141e2c4629a62ef9e79637e3b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:38:12.661737tests.unit.test_isorttest_convert_hangingtest_convert_hangingtests\unit\test_isort.pyfunction?S@??c@`nMMA7=== 6cb049a30141e2c4629a62ef9e79637e3b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:38:11.585562tests.unit.test_isorttest_length_sort_sectiontest_length_sort_sectiontests\unit\test_isort.pyfunction?+??4e@`pMMA7??= 6cb049a30141e2c4629a62ef9e79637e3b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:38:10.409808tests.unit.test_isorttest_length_sort_straighttest_length_sort_straighttests\unit\test_isort.pyfunction?@??٣;@` ( (b2MMA711= 6cb049a30141e2c4629a62ef9e79637e3b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:38:41.498808tests.unit.test_isorttest_order_by_typetest_order_by_typetests\unit\test_isort.pyfunction?/@??/؂c@`^1MMA7--= 6cb049a30141e2c4629a62ef9e79637e3b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:38:40.543138tests.unit.test_isorttest_atomic_modetest_atomic_modetests\unit\test_isort.pyfunction? D??~.1@`h0MMA777= 6cb049a30141e2c4629a62ef9e79637e3b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:38:39.475515tests.unit.test_isorttest_single_multilinetest_single_multilinetests\unit\test_isort.pyfunction???o@`h/MMA777= 6cb049a30141e2c4629a62ef9e79637e3b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:38:38.481874tests.unit.test_isorttest_multiline_importtest_multiline_importtests\unit\test_isort.pyfunction?M??[}cw@`|.MMA7KK= 6cb049a30141e2c4629a62ef9e79637e3b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:38:37.498975tests.unit.test_isorttest_relative_import_with_spacetest_relative_import_with_spacetests\unit\test_isort.pyfunction?ڀ??r+w@`j-MMA799= 6cb049a30141e2c4629a62ef9e79637e3b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:38:36.536846tests.unit.test_isorttest_balanced_wrappingtest_balanced_wrappingtests\unit\test_isort.pyfunction?Yc??l1+@`~,MMA7MM= 6cb049a30141e2c4629a62ef9e79637e3b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:38:35.594260tests.unit.test_isorttest_titled_and_footered_importstest_titled_and_footered_importstests\unit\test_isort.pyfunction?{??ۍœy@`h+MMA777= 6cb049a30141e2c4629a62ef9e79637e3b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:38:34.581558tests.unit.test_isorttest_footered_importstest_footered_importstests\unit\test_isort.pyfunction?ؾ??" @`d*MMA733= 6cb049a30141e2c4629a62ef9e79637e3b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:38:33.586597tests.unit.test_isorttest_titled_importstest_titled_importstests\unit\test_isort.pyfunction?[ ??~B8M@`,)MMA7{{= 6cb049a30141e2c4629a62ef9e79637e3b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:38:32.300378tests.unit.test_isorttest_force_single_line_imports_and_sort_within_sectionstest_force_single_line_imports_and_sort_within_sectionstests\unit\test_isort.pyfunction?N??6_{w5D@`(MMA7SS= 6cb049a30141e2c4629a62ef9e79637e3b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:38:31.316715tests.unit.test_isorttest_force_single_line_long_importstest_force_single_line_long_importstests\unit\test_isort.pyfunction???D$C@`'MMA7II= 6cb049a30141e2c4629a62ef9e79637e3b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:38:30.362262tests.unit.test_isorttest_force_single_line_importstest_force_single_line_importstests\unit\test_isort.pyfunction????2߯Ĕ@`&MMA7OO= 6cb049a30141e2c4629a62ef9e79637e3b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:38:29.348172tests.unit.test_isorttest_known_pattern_path_expansiontest_known_pattern_path_expansiontests\unit\test_isort.pyfunction? ??q@`%MMA7ee= 6cb049a30141e2c4629a62ef9e79637e3b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:38:28.333020tests.unit.test_isorttest_thirdy_party_overrides_standard_sectiontest_thirdy_party_overrides_standard_sectiontests\unit\test_isort.pyfunction?@??8`i@`$MMA7cc= 6cb049a30141e2c4629a62ef9e79637e3b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:38:27.361099tests.unit.test_isorttest_first_party_overrides_standard_sectiontest_first_party_overrides_standard_sectiontests\unit\test_isort.pyfunction???&˛@`  08@D\hx~dBMMA733= 6cb049a30141e2c4629a62ef9e79637e3b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:39:03.246405tests.unit.test_isorttest_split_positiontest_split_positiontests\unit\test_isort.pyfunction???AAe2u@_vAMMA7EE= 6cb049a30141e2c4629a62ef9e79637e3b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:39:01.947332tests.unit.test_isorttest_tab_character_in_importtest_tab_character_in_importtests\unit\test_isort.pyfunction?V@?? *]O@_l@MMA7;;= 6cb049a30141e2c4629a62ef9e79637e3b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:39:00.841800tests.unit.test_isorttest_long_line_commentstest_long_line_commentstests\unit\test_isort.pyfunction?x??M@_p?MMA7??= 6cb049a30141e2c4629a62ef9e79637e3b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:38:59.776858tests.unit.test_isorttest_same_line_statementstest_same_line_statementstests\unit\test_isort.pyfunction????za7@_d>MMA733= 6cb049a30141e2c4629a62ef9e79637e3b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:38:58.752527tests.unit.test_isorttest_auto_detectiontest_auto_detectiontests\unit\test_isort.pyfunction?.i??_:>@_x=MMA7GG= 6cb049a30141e2c4629a62ef9e79637e3b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:38:57.675380tests.unit.test_isorttest_correctly_placed_importstest_correctly_placed_importstests\unit\test_isort.pyfunction???Rb@_t<MMA7CC= 6cb049a30141e2c4629a62ef9e79637e3b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:38:56.670874tests.unit.test_isorttest_similar_to_std_librarytest_similar_to_std_librarytests\unit\test_isort.pyfunction?4??'O@_t;MMA7CC= 6cb049a30141e2c4629a62ef9e79637e3b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:38:55.696931tests.unit.test_isorttest_include_trailing_commatest_include_trailing_commatests\unit\test_isort.pyfunction?ȕ??Sћ@_ @^:MMA7--= 6cb049a30141e2c4629a62ef9e79637e3b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:38:54.711765tests.unit.test_isorttest_import_startest_import_startests\unit\test_isort.pyfunction???ơS+r@_@t9MMA7CC= 6cb049a30141e2c4629a62ef9e79637e3b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:38:53.681802tests.unit.test_isorttest_multiline_split_on_dottest_multiline_split_on_dottests\unit\test_isort.pyfunction?Dk?? #@_@b8MMA711= 6cb049a30141e2c4629a62ef9e79637e3b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:38:52.115846tests.unit.test_isorttest_keep_commentstest_keep_commentstests\unit\test_isort.pyfunction???o|@_@~7MMA7MM= 6cb049a30141e2c4629a62ef9e79637e3b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:38:50.005237tests.unit.test_isorttest_as_imports_with_line_lengthtest_as_imports_with_line_lengthtests\unit\test_isort.pyfunction@`?? /d@_@6MMA7OO= 6cb049a30141e2c4629a62ef9e79637e3b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:38:48.934301tests.unit.test_isorttest_combined_from_and_as_importstest_combined_from_and_as_importstests\unit\test_isort.pyfunction???QtR@_@l5MMA7;;= 6cb049a30141e2c4629a62ef9e79637e3b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:38:47.559083tests.unit.test_isorttest_settings_overwritetest_settings_overwritetests\unit\test_isort.pyfunction?`@??8X@_@4MMA7WW= 6cb049a30141e2c4629a62ef9e79637e3b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:38:46.012477tests.unit.test_isorttest_smart_lines_after_import_sectiontest_smart_lines_after_import_sectiontests\unit\test_isort.pyfunction?р??ָS<@_@ 3MMA7YY= 6cb049a30141e2c4629a62ef9e79637e3b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:38:44.041025tests.unit.test_isorttest_custom_lines_after_import_sectiontest_custom_lines_after_import_sectiontests\unit\test_isort.pyfunction?O??ek*@_@ :* 8 ( H ^ &P6:xSMMA7??= 6cb049a30141e2c4629a62ef9e79637e3b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:39:26.816267tests.unit.test_isorttest_other_file_encodingstest_other_file_encodingstests\unit\test_isort.pyfunction????/K@_@RMMA7]]= 6cb049a30141e2c4629a62ef9e79637e3b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:39:25.790263tests.unit.test_isorttest_import_split_is_word_boundary_awaretest_import_split_is_word_boundary_awaretests\unit\test_isort.pyfunction?&@???*@_@RQMMA7!!= 6cb049a30141e2c4629a62ef9e79637e3b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:39:24.404264tests.unit.test_isorttest_fcntltest_fcntltests\unit\test_isort.pyfunction? @??L @_pPMMA7??= 6cb049a30141e2c4629a62ef9e79637e3b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:39:23.237733tests.unit.test_isorttest_uses_jinja_variablestest_uses_jinja_variablestests\unit\test_isort.pyfunction?]5@?? =@_pOMMA7??= 6cb049a30141e2c4629a62ef9e79637e3b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:39:22.196075tests.unit.test_isorttest_force_grid_wrap_longtest_force_grid_wrap_longtests\unit\test_isort.pyfunction?_L??E@_fNMMA755= 6cb049a30141e2c4629a62ef9e79637e3b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:39:20.959764tests.unit.test_isorttest_force_grid_wraptest_force_grid_wraptests\unit\test_isort.pyfunction?w*??+o_q@_^MMMA7--= 6cb049a30141e2c4629a62ef9e79637e3b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:39:19.841256tests.unit.test_isorttest_consistencytest_consistencytests\unit\test_isort.pyfunction?P??5vq@_`LMMA7//= 6cb049a30141e2c4629a62ef9e79637e3b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:39:18.092299tests.unit.test_isorttest_top_commentstest_top_commentstests\unit\test_isort.pyfunction???*@_\KMMA7++= 6cb049a30141e2c4629a62ef9e79637e3b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:39:16.924706tests.unit.test_isorttest_from_firsttest_from_firsttests\unit\test_isort.pyfunction?h??17@_^JMMA7--= 6cb049a30141e2c4629a62ef9e79637e3b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:39:15.468590tests.unit.test_isorttest_from_endingtest_from_endingtests\unit\test_isort.pyfunction?d??ЖQ^@_ZIMMA7))= 6cb049a30141e2c4629a62ef9e79637e3b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:39:14.301801tests.unit.test_isorttest_zipimporttest_zipimporttests\unit\test_isort.pyfunction?q??YF(@_fHMMA755= 6cb049a30141e2c4629a62ef9e79637e3b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:39:12.049599tests.unit.test_isorttest_sticky_commentstest_sticky_commentstests\unit\test_isort.pyfunction@ݐ??~s@}t@_\GMMA7++= 6cb049a30141e2c4629a62ef9e79637e3b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:39:10.065863tests.unit.test_isorttest_glob_knowntest_glob_knowntests\unit\test_isort.pyfunction?~??B@h@_ FMMA7[[= 6cb049a30141e2c4629a62ef9e79637e3b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:39:08.852499tests.unit.test_isorttest_custom_sections_exception_handlingtest_custom_sections_exception_handlingtests\unit\test_isort.pyfunction?.p@??[ !V@_nEMMA755= 6cb049a30141e2c4629a62ef9e79637e3b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:39:07.630829tests.unit.test_isorttest_custom_sectionstest_custom_sectionstests\unit\test_isort.pyfunction?B.???Pvo@_jDMMA799= 6cb049a30141e2c4629a62ef9e79637e3b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:39:06.473521tests.unit.test_isorttest_placement_controltest_placement_controltests\unit\test_isort.pyfunction?F@??7/ @_dCMMA733= 6cb049a30141e2c4629a62ef9e79637e3b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:39:04.987862tests.unit.test_isorttest_place_commentstest_place_commentstests\unit\test_isort.pyfunction?v??Up>' @_ L   4DJXP^RLcMMA7QQ= 6cb049a30141e2c4629a62ef9e79637e3b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:39:46.526016tests.unit.test_isorttest_sorting_with_two_top_commentstest_sorting_with_two_top_commentstests\unit\test_isort.pyfunction?du??ffa@_&bMMA7WW= 6cb049a30141e2c4629a62ef9e79637e3b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:39:45.409675tests.unit.test_isorttest_sort_within_section_case_honoredtest_sort_within_section_case_honoredtests\unit\test_isort.pyfunction?@??j @_&naMMA7=== 6cb049a30141e2c4629a62ef9e79637e3b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:39:44.249342tests.unit.test_isorttest_sort_within_sectiontest_sort_within_sectiontests\unit\test_isort.pyfunction?3??n~@_%`MMA7SS= 6cb049a30141e2c4629a62ef9e79637e3b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:39:43.052693tests.unit.test_isorttest_alphabetic_sorting_no_newlinestest_alphabetic_sorting_no_newlinestests\unit\test_isort.pyfunction?ߌ??hPH@_$n_MMA7=== 6cb049a30141e2c4629a62ef9e79637e3b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:39:41.840451tests.unit.test_isorttest_pyproject_conf_filetest_pyproject_conf_filetests\unit\test_isort.pyfunction?%=@??fY (2@_v^MMA7EE= 6cb049a30141e2c4629a62ef9e79637e3b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:39:40.348161tests.unit.test_isorttest_sections_parsed_correcttest_sections_parsed_correcttests\unit\test_isort.pyfunction?q??ֶ̉]@_l]MMA7;;= 6cb049a30141e2c4629a62ef9e79637e3b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:39:38.600786tests.unit.test_isorttest_shouldnt_add_linestest_shouldnt_add_linestests\unit\test_isort.pyfunction???2P3@_b\MMA711= 6cb049a30141e2c4629a62ef9e79637e3b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:39:37.527733tests.unit.test_isorttest_basic_commenttest_basic_commenttests\unit\test_isort.pyfunction?j??=q@_p[MMA7??= 6cb049a30141e2c4629a62ef9e79637e3b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:39:36.533164tests.unit.test_isorttest_top_of_line_commentstest_top_of_line_commentstests\unit\test_isort.pyfunction?'s??Ÿ|@ @_vZMMA7EE= 6cb049a30141e2c4629a62ef9e79637e3b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:39:35.565464tests.unit.test_isorttest_comments_not_duplicatedtest_comments_not_duplicatedtests\unit\test_isort.pyfunction?s??iY @_YMMA7QQ= 6cb049a30141e2c4629a62ef9e79637e3b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:39:34.344512tests.unit.test_isorttest_alphabetic_sorting_multi_linetest_alphabetic_sorting_multi_linetests\unit\test_isort.pyfunction?J??$ <@_lXMMA7;;= 6cb049a30141e2c4629a62ef9e79637e3b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:39:32.701550tests.unit.test_isorttest_alphabetic_sortingtest_alphabetic_sortingtests\unit\test_isort.pyfunction? ??:)@_tWMMA7CC= 6cb049a30141e2c4629a62ef9e79637e3b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:39:31.452042tests.unit.test_isorttest_comment_at_top_of_filetest_comment_at_top_of_filetests\unit\test_isort.pyfunction???@_@VMMA7UU= 6cb049a30141e2c4629a62ef9e79637e3b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:39:30.015708tests.unit.test_isorttest_encoding_not_in_first_two_linestest_encoding_not_in_first_two_linestests\unit\test_isort.pyfunction???.n@_vUMMA7EE= 6cb049a30141e2c4629a62ef9e79637e3b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:39:28.946989tests.unit.test_isorttest_encoding_not_in_commenttest_encoding_not_in_commenttests\unit\test_isort.pyfunction?7@??I@_TMMA7QQ= 6cb049a30141e2c4629a62ef9e79637e3b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:39:27.789763tests.unit.test_isorttest_other_file_encodings_in_placetest_other_file_encodings_in_placetests\unit\test_isort.pyfunction?8@??@_@       ,,,"4HB( rMMA7SS= 6cb049a30141e2c4629a62ef9e79637e3b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:40:03.792321tests.unit.test_isorttest_import_line_mangles_issues_491test_import_line_mangles_issues_491tests\unit\test_isort.pyfunction???.DZ@_8qMMA7ee= 6cb049a30141e2c4629a62ef9e79637e3b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:40:02.687412tests.unit.test_isorttest_wildcard_import_without_space_issue_496test_wildcard_import_without_space_issue_496tests\unit\test_isort.pyfunction?Wc@??Xτ@_4pMMA7QQ= 6cb049a30141e2c4629a62ef9e79637e3b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:40:01.584293tests.unit.test_isorttest_import_inside_class_issue_432test_import_inside_class_issue_432tests\unit\test_isort.pyfunction?h??~H{@_,@hoMMA777= 6cb049a30141e2c4629a62ef9e79637e3b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:40:00.464679tests.unit.test_isorttest_long_single_linetest_long_single_linetests\unit\test_isort.pyfunction???FHk@_,@jnMMA799= 6cb049a30141e2c4629a62ef9e79637e3b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:39:59.348255tests.unit.test_isorttest_sys_path_mutationtest_sys_path_mutationtests\unit\test_isort.pyfunction?,??@_+mMMA7UU= 6cb049a30141e2c4629a62ef9e79637e3b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:39:58.268786tests.unit.test_isorttest_exists_case_sensitive_directorytest_exists_case_sensitive_directorytests\unit\test_isort.pyfunction???z]³7@_+|lMMA7KK= 6cb049a30141e2c4629a62ef9e79637e3b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:39:57.230532tests.unit.test_isorttest_exists_case_sensitive_filetest_exists_case_sensitive_filetests\unit\test_isort.pyfunction?CE??{Qx@_+|kMMA7KK= 6cb049a30141e2c4629a62ef9e79637e3b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:39:56.151227tests.unit.test_isorttest_third_party_case_sensitivetest_third_party_case_sensitivetests\unit\test_isort.pyfunction???'Ny1@_+^jMMA7--= 6cb049a30141e2c4629a62ef9e79637e3b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:39:54.988701tests.unit.test_isorttest_plone_styletest_plone_styletests\unit\test_isort.pyfunction????rJV@_+viMMA7EE= 6cb049a30141e2c4629a62ef9e79637e3b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:39:53.681509tests.unit.test_isorttest_function_with_docstringtest_function_with_docstringtests\unit\test_isort.pyfunction???ZB@_+zhMMA7II= 6cb049a30141e2c4629a62ef9e79637e3b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:39:52.605891tests.unit.test_isorttest_import_by_paren_issue_460test_import_by_paren_issue_460tests\unit\test_isort.pyfunction?@@??sM@_*zgMMA7II= 6cb049a30141e2c4629a62ef9e79637e3b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:39:51.606097tests.unit.test_isorttest_import_by_paren_issue_375test_import_by_paren_issue_375tests\unit\test_isort.pyfunction?dn??Y3g@_*fMMA7QQ= 6cb049a30141e2c4629a62ef9e79637e3b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:39:50.560927tests.unit.test_isorttest_no_additional_lines_issue_358test_no_additional_lines_issue_358tests\unit\test_isort.pyfunction?f??P0K@_*zeMMA7AA= 6cb049a30141e2c4629a62ef9e79637e3b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:39:49.171067tests.unit.test_isorttest_forced_sepatate_globstest_forced_sepatate_globstests\unit\test_isort.pyfunction????V)d@_'@tdMMA7CC= 6cb049a30141e2c4629a62ef9e79637e3b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:39:47.634041tests.unit.test_isorttest_lines_between_sectionstest_lines_between_sectionstests\unit\test_isort.pyfunction?2c??(*M.@_&  V>BMMA7= 6cb049a30141e2c4629a62ef9e79637e3b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:40:21.121994tests.unit.test_isorttest_force_sort_within_sections_with_reverse_relative_importstest_force_sort_within_sections_with_reverse_relative_importstests\unit\test_isort.pyfunction?=m@????@_X(MMA7ww= 6cb049a30141e2c4629a62ef9e79637e3b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:40:19.692597tests.unit.test_isorttest_force_sort_within_sections_with_relative_importstest_force_sort_within_sections_with_relative_importstests\unit\test_isort.pyfunction?u@??``"@_W(~MMA7ww= 6cb049a30141e2c4629a62ef9e79637e3b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:40:18.387312tests.unit.test_isorttest_sort_within_sections_with_force_to_top_issue_473test_sort_within_sections_with_force_to_top_issue_473tests\unit\test_isort.pyfunction???w@_O}MMA7cc= 6cb049a30141e2c4629a62ef9e79637e3b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:40:16.496490tests.unit.test_isorttest_sort_within_section_comments_issue_436test_sort_within_section_comments_issue_436tests\unit\test_isort.pyfunction???;l֣@_N*|MMA7yy= 6cb049a30141e2c4629a62ef9e79637e3b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:40:15.315898tests.unit.test_isorttest_inconsistent_behavior_in_python_2_and_3_issue_479test_inconsistent_behavior_in_python_2_and_3_issue_479tests\unit\test_isort.pyfunction?X??W: Q@_N.{MMA7}}= 6cb049a30141e2c4629a62ef9e79637e3b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:40:14.187439tests.unit.test_isorttest_import_case_produces_inconsistent_results_issue_472test_import_case_produces_inconsistent_results_issue_472tests\unit\test_isort.pyfunction???WEڏ:@_MzMMA7]]= 6cb049a30141e2c4629a62ef9e79637e3b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:40:12.592300tests.unit.test_isorttest_import_wraps_with_comment_issue_471test_import_wraps_with_comment_issue_471tests\unit\test_isort.pyfunction?'J??Z㢅@_M@jyMMA799= 6cb049a30141e2c4629a62ef9e79637e3b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:40:11.411969tests.unit.test_isorttest_ignore_whitespacetest_ignore_whitespacetests\unit\test_isort.pyfunction?g4??cj9y@_L$xMMA7ss= 6cb049a30141e2c4629a62ef9e79637e3b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:40:10.243564tests.unit.test_isorttest_strict_whitespace_no_closing_newline_issue_676test_strict_whitespace_no_closing_newline_issue_676tests\unit\test_isort.pyfunction?D@??2ej@_LwMMA7OO= 6cb049a30141e2c4629a62ef9e79637e3b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:40:09.229985tests.unit.test_isorttest_strict_whitespace_by_defaulttest_strict_whitespace_by_defaulttests\unit\test_isort.pyfunction?Ҳ???E@_JvMMA7WW= 6cb049a30141e2c4629a62ef9e79637e3b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:40:08.092311tests.unit.test_isorttest_long_alias_using_paren_issue_957test_long_alias_using_paren_issue_957tests\unit\test_isort.pyfunction???ckX@_J~uMMA7MM= 6cb049a30141e2c4629a62ef9e79637e3b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:40:06.881057tests.unit.test_isorttest_alias_using_paren_issue_466test_alias_using_paren_issue_466tests\unit\test_isort.pyfunction? @??\o@_EtMMA7SS= 6cb049a30141e2c4629a62ef9e79637e3b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:40:05.863823tests.unit.test_isorttest_import_line_mangles_issues_439test_import_line_mangles_issues_439tests\unit\test_isort.pyfunction???P@_D@sMMA7SS= 6cb049a30141e2c4629a62ef9e79637e3b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:40:04.857543tests.unit.test_isorttest_import_line_mangles_issues_505test_import_line_mangles_issues_505tests\unit\test_isort.pyfunction?vi??EYj@_D@  b X \ H"~MMA7MM= 6cb049a30141e2c4629a62ef9e79637e3b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:40:43.791811tests.unit.test_isorttest_relative_import_of_a_moduletest_relative_import_of_a_moduletests\unit\test_isort.pyfunction?9@??@_ld MMA733= 6cb049a30141e2c4629a62ef9e79637e3b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:40:42.505423tests.unit.test_isorttest_no_inline_sorttest_no_inline_sorttests\unit\test_isort.pyfunction?C!??ֹ@_l MMA7QQ= 6cb049a30141e2c4629a62ef9e79637e3b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:40:41.528095tests.unit.test_isorttest_no_lines_before_empty_sectiontest_no_lines_before_empty_sectiontests\unit\test_isort.pyfunction?R??Ou@_jr MMA7AA= 6cb049a30141e2c4629a62ef9e79637e3b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:40:40.523794tests.unit.test_isorttest_not_splitted_sectionstest_not_splitted_sectionstests\unit\test_isort.pyfunction?J??)j]@_j MMA7mm= 6cb049a30141e2c4629a62ef9e79637e3b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:40:39.282166tests.unit.test_isorttest_ensure_line_endings_are_preserved_issue_493test_ensure_line_endings_are_preserved_issue_493tests\unit\test_isort.pyfunction???4̫V@_i6 MMA7= 6cb049a30141e2c4629a62ef9e79637e3b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:40:37.261080tests.unit.test_isorttest_ensure_as_imports_sort_correctly_within_from_imports_issue_590test_ensure_as_imports_sort_correctly_within_from_imports_issue_590tests\unit\test_isort.pyfunction@@_iMMA7]]= 6cb049a30141e2c4629a62ef9e79637e3b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:40:35.292256tests.unit.test_isorttest_ensure_async_methods_work_issue_537test_ensure_async_methods_work_issue_537tests\unit\test_isort.pyfunction?G??t@_h"MMA7qq= 6cb049a30141e2c4629a62ef9e79637e3b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:40:33.199927tests.unit.test_isorttest_pylint_comments_incorrectly_wrapped_issue_571test_pylint_comments_incorrectly_wrapped_issue_571tests\unit\test_isort.pyfunction@r@??46@_hMMA7__= 6cb049a30141e2c4629a62ef9e79637e3b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:40:32.076619tests.unit.test_isorttest_long_import_wrap_support_with_mode_2test_long_import_wrap_support_with_mode_2tests\unit\test_isort.pyfunction?e@??D@_h@xMMA7GG= 6cb049a30141e2c4629a62ef9e79637e3b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:40:29.941713tests.unit.test_isorttest_no_extra_lines_issue_557test_no_extra_lines_issue_557tests\unit\test_isort.pyfunction@??dF@_gMMA7UU= 6cb049a30141e2c4629a62ef9e79637e3b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:40:27.878611tests.unit.test_isorttest_future_below_encoding_issue_545test_future_below_encoding_issue_545tests\unit\test_isort.pyfunction@<`??JN]@_a@,MMA7{{= 6cb049a30141e2c4629a62ef9e79637e3b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:40:26.055267tests.unit.test_isorttest_correct_number_of_new_lines_with_comment_issue_435test_correct_number_of_new_lines_with_comment_issue_435tests\unit\test_isort.pyfunction?$??ZƜض@_a@<MMA7 = 6cb049a30141e2c4629a62ef9e79637e3b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:40:24.604114tests.unit.test_isorttest_reverse_sort_relative_in_force_sorted_sections_issue_1659test_reverse_sort_relative_in_force_sorted_sections_issue_1659tests\unit\test_isort.pyfunction???%@_a@*MMA7yy= 6cb049a30141e2c4629a62ef9e79637e3b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:40:22.608503tests.unit.test_isorttest_sort_relative_in_force_sorted_sections_issue_1659test_sort_relative_in_force_sorted_sections_issue_1659tests\unit\test_isort.pyfunction? ??o^@_Y  rRX8BVcyXMMA7!-= 6cb049a30141e2c4629a62ef9e79637e3b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:41:17.531115tests.unit.test_isorttest_quiettest_quiet[True]tests\unit\test_isort.pyfunction?Y@??ԝ@_lMMA7ii= 6cb049a30141e2c4629a62ef9e79637e3b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:41:01.667046tests.unit.test_isorttest_to_ensure_no_unexpected_changes_issue_666test_to_ensure_no_unexpected_changes_issue_666tests\unit\test_isort.pyfunction@??Bdd@_l8MMA7= 6cb049a30141e2c4629a62ef9e79637e3b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:40:58.532679tests.unit.test_isorttest_to_ensure_importing_from_imports_module_works_issue_662test_to_ensure_importing_from_imports_module_works_issue_662tests\unit\test_isort.pyfunction@Р??/@@@_lMMA7ii= 6cb049a30141e2c4629a62ef9e79637e3b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:40:55.626281tests.unit.test_isorttest_escaped_no_parens_sort_with_first_commenttest_escaped_no_parens_sort_with_first_commenttests\unit\test_isort.pyfunction@ ??>@_lMMA7cc= 6cb049a30141e2c4629a62ef9e79637e3b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:40:50.722683tests.unit.test_isorttest_escaped_parens_sort_with_first_commenttest_escaped_parens_sort_with_first_commenttests\unit\test_isort.pyfunction@??aq@_lMMA7WW= 6cb049a30141e2c4629a62ef9e79637e3b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:40:47.680188tests.unit.test_isorttest_escaped_parens_sort_with_commenttest_escaped_parens_sort_with_commenttests\unit\test_isort.pyfunction@,??.{ϒM@_lnMMA7=== 6cb049a30141e2c4629a62ef9e79637e3b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:40:45.725191tests.unit.test_isorttest_escaped_parens_sorttest_escaped_parens_sorttests\unit\test_isort.pyfunction???ɎU@_l + 2 A P x p`FZh`x:J,MMA7= 6cb049a30141e2c4629a62ef9e79637e3b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:41:41.094171tests.unit.test_isorttest_ensure_support_for_non_typed_but_cased_alphabetic_sort_issue_890test_ensure_support_for_non_typed_but_cased_alphabetic_sort_issue_890tests\unit\test_isort.pyfunction@a??y;׭@_:+MMA7= 6cb049a30141e2c4629a62ef9e79637e3b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:41:38.978761tests.unit.test_isorttest_extract_multiline_output_wrap_setting_from_a_config_filetest_extract_multiline_output_wrap_setting_from_a_config_filetests\unit\test_isort.pyfunction@`??[@_d*MMA733= 6cb049a30141e2c4629a62ef9e79637e3b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:41:36.920449tests.unit.test_isorttest_noqa_issue_679test_noqa_issue_679tests\unit\test_isort.pyfunction@@@??ߴs@_)MMA7SS= 6cb049a30141e2c4629a62ef9e79637e3b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:41:35.827251tests.unit.test_isorttest_all_imports_from_single_moduletest_all_imports_from_single_moduletests\unit\test_isort.pyfunction?#??gK@_n(MMA7=== 6cb049a30141e2c4629a62ef9e79637e3b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:41:34.710548tests.unit.test_isorttest_multiple_as_importstest_multiple_as_importstests\unit\test_isort.pyfunction???*no@_w@h'MMA777= 6cb049a30141e2c4629a62ef9e79637e3b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:41:33.453199tests.unit.test_isorttest_unwrap_issue_762test_unwrap_issue_762tests\unit\test_isort.pyfunction???`@_w@&MMA7ee= 6cb049a30141e2c4629a62ef9e79637e3b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:41:31.317467tests.unit.test_isorttest_inconsistent_relative_imports_issue_577test_inconsistent_relative_imports_issue_577tests\unit\test_isort.pyfunction@@??-(@_w@ %MMA7[[= 6cb049a30141e2c4629a62ef9e79637e3b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:41:29.169096tests.unit.test_isorttest_reverse_relative_imports_issue_417test_reverse_relative_imports_issue_417tests\unit\test_isort.pyfunction@ ?? o@_w@$MMA7SS= 6cb049a30141e2c4629a62ef9e79637e3b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:41:27.555840tests.unit.test_isorttest_comments_not_removed_issue_576test_comments_not_removed_issue_576tests\unit\test_isort.pyfunction?P??J u@_w@T#MMA7##= 6cb049a30141e2c4629a62ef9e79637e3b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:41:25.977975tests.unit.test_isorttest_brokentest_brokentests\unit\test_isort.pyfunction???,T9@_w@m"MMA7)O= 6cb049a30141e2c4629a62ef9e79637e3b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:41:23.217878tests.unit.test_isorttest_skip_globtest_skip_glob[skip_glob_assert2]tests\unit\test_isort.pyfunction@ ?? o@_w@m!MMA7)O= 6cb049a30141e2c4629a62ef9e79637e3b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:41:21.930441tests.unit.test_isorttest_skip_globtest_skip_glob[skip_glob_assert1]tests\unit\test_isort.pyfunction?&??;n5T@_w@u MMA7)O= 6cb049a30141e2c4629a62ef9e79637e3b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:41:20.841946tests.unit.test_isorttest_skip_globtest_skip_glob[skip_glob_assert0]tests\unit\test_isort.pyfunction?.R???|@_w@fMMA7/;= 6cb049a30141e2c4629a62ef9e79637e3b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:41:19.715498tests.unit.test_isorttest_safety_skipstest_safety_skips[True]tests\unit\test_isort.pyfunction?@??ug@_x@gMMA7/== 6cb049a30141e2c4629a62ef9e79637e3b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:41:18.673796tests.unit.test_isorttest_safety_skipstest_safety_skips[False]tests\unit\test_isort.pyfunction?h??s=@_x@ z f n r jP&>.:\z^;MMA7--= 6cb049a30141e2c4629a62ef9e79637e3b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:42:18.659062tests.unit.test_isorttest_isort_splittest_isort_splittests\unit\test_isort.pyfunction??? I\@_Z:MMA7))= 6cb049a30141e2c4629a62ef9e79637e3b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:42:17.139438tests.unit.test_isorttest_isort_offtest_isort_offtests\unit\test_isort.pyfunction?9??s N@_p9MMA7??= 6cb049a30141e2c4629a62ef9e79637e3b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:42:15.564326tests.unit.test_isorttest_isort_nested_importstest_isort_nested_importstests\unit\test_isort.pyfunction?٣@??~tx@_ 8MMA7[[= 6cb049a30141e2c4629a62ef9e79637e3b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:42:13.166650tests.unit.test_isorttest_isort_with_single_character_importtest_isort_with_single_character_importtests\unit\test_isort.pyfunction@b??u(@_d7MMA733= 6cb049a30141e2c4629a62ef9e79637e3b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:42:11.608027tests.unit.test_isorttest_python_versiontest_python_versiontests\unit\test_isort.pyfunction?z??[)b@_p6MMA7??= 6cb049a30141e2c4629a62ef9e79637e3b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:42:08.795018tests.unit.test_isorttest_move_class_issue_751test_move_class_issue_751tests\unit\test_isort.pyfunction@O??cl@_5MMA7GG= 6cb049a30141e2c4629a62ef9e79637e3b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:42:05.998385tests.unit.test_isorttest_pyi_formatting_issue_942test_pyi_formatting_issue_942tests\unit\test_isort.pyfunction@m???@_.4MMA7}}= 6cb049a30141e2c4629a62ef9e79637e3b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:42:02.667454tests.unit.test_isorttest_isort_ensures_blank_line_between_import_and_commenttest_isort_ensures_blank_line_between_import_and_commenttests\unit\test_isort.pyfunction@ GV??ZEO5@_3MMA7]]= 6cb049a30141e2c4629a62ef9e79637e3b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:41:58.960469tests.unit.test_isorttest_isort_multiline_with_tab_issue_1714test_isort_multiline_with_tab_issue_1714tests\unit\test_isort.pyfunction@ g`???@_2MMA7SS= 6cb049a30141e2c4629a62ef9e79637e3b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:41:55.944336tests.unit.test_isorttest_isort_keeps_comments_issue_691test_isort_keeps_comments_issue_691tests\unit\test_isort.pyfunction@ 7 ??GA-Q@_x1MMA7GG= 6cb049a30141e2c4629a62ef9e79637e3b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:41:53.414227tests.unit.test_isorttest_import_heading_issue_905test_import_heading_issue_905tests\unit\test_isort.pyfunction@@??XT@_t0MMA7CC= 6cb049a30141e2c4629a62ef9e79637e3b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:41:50.915973tests.unit.test_isorttest_failing_file_check_916test_failing_file_check_916tests\unit\test_isort.pyfunction@k@??6Զa@_/MMA7kk= 6cb049a30141e2c4629a62ef9e79637e3b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:41:48.489331tests.unit.test_isorttest_standard_library_deprecates_user_issue_778test_standard_library_deprecates_user_issue_778tests\unit\test_isort.pyfunction@??zxu=@_<.MMA7 = 6cb049a30141e2c4629a62ef9e79637e3b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:41:46.193006tests.unit.test_isorttest_to_ensure_correctly_handling_of_whitespace_only_issue_811test_to_ensure_correctly_handling_of_whitespace_only_issue_811tests\unit\test_isort.pyfunction@??k@_6-MMA7= 6cb049a30141e2c4629a62ef9e79637e3b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:41:43.676970tests.unit.test_isorttest_to_ensure_empty_line_not_added_to_file_start_issue_889test_to_ensure_empty_line_not_added_to_file_start_issue_889tests\unit\test_isort.pyfunction@ʠ?? kb{@_  : B X ` fr~KMMA7MM= 6cb049a30141e2c4629a62ef9e79637e3b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:42:45.205047tests.unit.test_isorttest_combine_star_comments_abovetest_combine_star_comments_abovetests\unit\test_isort.pyfunction?g??g|~@_|JMMA7CC= 6cb049a30141e2c4629a62ef9e79637e3b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:42:43.904556tests.unit.test_isorttest_python_future_categorytest_python_future_categorytests\unit\test_isort.pyfunction?n@???ON@_jIMMA799= 6cb049a30141e2c4629a62ef9e79637e3b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:42:42.692013tests.unit.test_isorttest_no_lines_too_longtest_no_lines_too_longtests\unit\test_isort.pyfunction?}??NvXW@_|HMMA7KK= 6cb049a30141e2c4629a62ef9e79637e3b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:42:41.625754tests.unit.test_isorttest_no_sections_with_as_importtest_no_sections_with_as_importtests\unit\test_isort.pyfunction???#7@_vGMMA7EE= 6cb049a30141e2c4629a62ef9e79637e3b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:42:40.653793tests.unit.test_isorttest_no_sections_with_futuretest_no_sections_with_futuretests\unit\test_isort.pyfunction?w??}z%@_hFMMA777= 6cb049a30141e2c4629a62ef9e79637e3b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:42:39.437459tests.unit.test_isorttest_as_imports_mixedtest_as_imports_mixedtests\unit\test_isort.pyfunction???;}@_jEMMA799= 6cb049a30141e2c4629a62ef9e79637e3b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:42:38.067679tests.unit.test_isorttest_parens_in_commenttest_parens_in_commenttests\unit\test_isort.pyfunction?@??ȽȠ@_XDMMA777= 6cb049a30141e2c4629a62ef9e79637e3b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:42:36.578919tests.unit.test_isorttest_multiple_aliasestest_multiple_aliasestests\unit\test_isort.pyfunction?l@_pCMMA7??= 6cb049a30141e2c4629a62ef9e79637e3b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:42:35.572556tests.unit.test_isorttest_comments_top_of_filetest_comments_top_of_filetests\unit\test_isort.pyfunction???C @_vBMMA7EE= 6cb049a30141e2c4629a62ef9e79637e3b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:42:34.469770tests.unit.test_isorttest_nested_comment_handlingtest_nested_comment_handlingtests\unit\test_isort.pyfunction?T??vҰ@_tAMMA7CC= 6cb049a30141e2c4629a62ef9e79637e3b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:42:32.764842tests.unit.test_isorttest_single_line_exclusionstest_single_line_exclusionstests\unit\test_isort.pyfunction???~:@_f@MMA755= 6cb049a30141e2c4629a62ef9e79637e3b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:42:30.639256tests.unit.test_isorttest_noqa_issue_1065test_noqa_issue_1065tests\unit\test_isort.pyfunction@@??W@_t?MMA7CC= 6cb049a30141e2c4629a62ef9e79637e3b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:42:28.046258tests.unit.test_isorttest_top_level_import_ordertest_top_level_import_ordertests\unit\test_isort.pyfunction?5P??e@_`>MMA7//= 6cb049a30141e2c4629a62ef9e79637e3b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:42:25.166279tests.unit.test_isorttest_cdef_supporttest_cdef_supporttests\unit\test_isort.pyfunction@ڍ`??g癪@_n=MMA755= 6cb049a30141e2c4629a62ef9e79637e3b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:42:21.686167tests.unit.test_isorttest_cimport_supporttest_cimport_supporttests\unit\test_isort.pyfunction@ 所???C f׬@_l<MMA7;;= 6cb049a30141e2c4629a62ef9e79637e3b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:42:19.980676tests.unit.test_isorttest_comment_look_aliketest_comment_look_aliketests\unit\test_isort.pyfunction???8@_  "   "tQMMA7CC= 6cb049a30141e2c4629a62ef9e79637e3b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:42:52.951726tests.unit.test_isorttest_find_imports_in_streamtest_find_imports_in_streamtests\unit\test_isort.pyfunction?b5??^`@_@pPMMA7??= 6cb049a30141e2c4629a62ef9e79637e3b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:42:51.588782tests.unit.test_isorttest_find_imports_in_codetest_find_imports_in_codetests\unit\test_isort.pyfunction?.??)Q@_@xOMMA7GG= 6cb049a30141e2c4629a62ef9e79637e3b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:42:49.676095tests.unit.test_isorttest_combine_straight_importstest_combine_straight_importstests\unit\test_isort.pyfunction? ??ߛ6@_bNMMA711= 6cb049a30141e2c4629a62ef9e79637e3b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:42:48.278678tests.unit.test_isorttest_only_sectionstest_only_sectionstests\unit\test_isort.pyfunction??? p~u@_MMMA7ii= 6cb049a30141e2c4629a62ef9e79637e3b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:42:47.289710tests.unit.test_isorttest_deprecated_settings_no_warn_in_quiet_modetest_deprecated_settings_no_warn_in_quiet_modetests\unit\test_isort.pyfunction???ĵN@T@_nLMMA7=== 6cb049a30141e2c4629a62ef9e79637e3b6dbb3ba9adaac90d99a9df3396d5a12023-01-23T10:42:46.247856tests.unit.test_isorttest_deprecated_settingstest_deprecated_settingstests\unit\test_isort.pyfunction?\)??!@_isort-6.0.1/CHANGELOG.md0000644000000000000000000011214613615410400011414 0ustar00Changelog ========= NOTE: isort follows the [semver](https://semver.org/) versioning standard. Find out more about isort's release policy [here](https://pycqa.github.io/isort/docs/major_releases/release_policy). ### 5.13.2 December 13 2023 - Apply the bracket fix from issue #471 only for use_parentheses=True (#2184) @bp72 - Confine pre-commit to stages (#2213) @davidculley - Fixed colors extras (#2212) @staticdev ### 5.13.1 December 11 2023 - Fixed integration tests (#2208) @bp72 - Fixed normalizing imports from more than one level of parent modules (issue/2152) (#2191) @bp72 - Remove optional dependencies without extras (#2207) @staticdev ### 5.13.0 December 9 2023 - Cleanup deprecated extras (#2089) @staticdev - Fixed #1989: settings lookup when working in stream based mode - Fixed 80 line length for wemake linter (#2183) @skatromb - Add support for Python 3.12 (#2175) @hugovk - Fixed: add newest version to pre-commit docs (#2190) @AzulGarza - Fixed assertions in test_git_hook (#2196) @mgorny - Removed check for include_trailing_comma for the Hanging Indent wrap mode (#2192) @bp72 - Use the standard library tomllib on sufficiently new python (#2202) @eli-schwartz - Update pre-commit.md version number (#2197) @nicobako - doc: Update black_compatibility.md (#2177) @JSS95 - Fixed safety sept 2023 (#2178) @staticdev - docs: fix black profile documentation (#2163) @nijel - Fixed typo: indended -> indented (#2161) @vadimkerr - Docs(configuration/options.md): fix missing trailing spaces for hard linebreak (#2157) @JoeyTeng - Update pre-commit.md (#2148) @godiard - chore: move configurations to pyproject.toml (#2115) @SauravMaheshkar - Fixed typo in README (#2112) @stefmolin - Update version in pre-commit setup to avoid installation issue with poetry (#2103) @stefmolin - Skip .pytype directory by default. (#2098) @manueljacob - Fixed a tip block styling in the Config Files section (#2097) @Klavionik - Do not cache configuration files (#1995) @kaste - Derive settings_path from --filename (#1992) @kaste - Fixed year of version 5.12.0 in CHANGELOG.md (#2082) @DjLegolas ### 5.12.0 January 28 2023 - Removed support for Python 3.7 - Fixed incompatiblity with latest poetry version - Added support for directory limitations within built in git hook ### 5.11.5 January 30 2023 [hotfix] - Fixed incompatiblity with latest poetry version ### 5.11.4 December 21 2022 - Fixed #2038 (again): stop installing documentation files to top-level site-packages (#2057) @mgorny - CI: only run release workflows for upstream (#2052) @hugovk - Tests: remove obsolete toml import from the test suite (#1978) @mgorny - CI: bump Poetry 1.3.1 (#2058) @staticdev ### 5.11.3 December 16 2022 - Fixed #2007: settings for py3.11 (#2040) @staticdev - Fixed #2038: packaging pypoetry (#2042) @staticdev - Docs: renable portray (#2043) @timothycrosley - Ci: add minimum GitHub token permissions for workflows (#1969) @varunsh-coder - Ci: general CI improvements (#2041) @staticdev - Ci: add release workflow (#2026) @staticdev ### 5.11.2 December 12 2022 - Hotfix #2034: isort --version is not accurate on 5.11.x releases (#2034) @gschaffner ### 5.11.1 December 12 2022 - Hotfix #2031: only call `colorama.init` if `colorama` is available (#2032) @tomaarsen ### 5.11.0 December 12 2022 - Added official support for Python 3.11 (#1996, #2008, #2011) @staticdev - Dropped support for Python 3.6 (#2019) @barrelful - Fixed problematic tests (#2021, #2022) @staticdev - Fixed #1960: Rich compatibility (#1961) @ofek - Fixed #1945, #1986: Python 4.0 upper bound dependency resolving issues @staticdev - Fixed Pyodide CDN URL (#1991) @andersk - Docs: clarify description of use_parentheses (#1941) @mgedmin - Fixed #1976: `black` compatibility for `.pyi` files @XuehaiPan - Implemented #1683: magic trailing comma option (#1876) @legau - Add missing space in unrecoverable exception message (#1933) @andersk - Fixed #1895: skip-gitignore: use allow list, not deny list @bmalehorn - Fixed #1917: infinite loop for unmatched parenthesis (#1919) @anirudnits - Docs: shared profiles (#1896) @matthewhughes934 - Fixed build-backend values in the example plugins (#1892) @mgorny - Remove reference to jamescurtin/isort-action (#1885) @AndrewLane - Split long cython import lines (#1931) @davidcollins001 - Update plone profile: copy of `black`, plus three settings. (#1926) @mauritsvanrees - Fixed #1815, #1862: Add a command-line flag to sort all re-exports (#1863) @parafoxia - Fixed #1854: `lines_before_imports` appending lines after comments (#1861) @legau - Remove redundant `multi_line_output = 3` from "Compatibility with black" (#1858) @jdufresne - Add tox config example (#1856) @umonaca - Docs: add examples for frozenset and tuple settings (#1822) @sgaist - Docs: add multiple config documentation (#1850) @anirudnits ### 5.10.1 November 8 2021 - Fixed #1819: Occasional inconsistency with multiple src paths. - Fixed #1840: skip_file ignored when on the first docstring line ### 5.10.0 November 3 2021 - Implemented #1796: Switch to `tomli` for pyproject.toml configuration loader. - Fixed #1801: CLI bug (--exend-skip-glob, overrides instead of extending). - Fixed #1802: respect PATH customization in nested calls to git. - Fixed #1838: Append only with certain code snippets incorrectly adds imports. - Added official support for Python 3.10 #### Potentially breaking changes: - Fixed #1785: `_ast` module incorrectly excluded from stdlib definition. ### 5.9.3 July 28 2021 - Improved text of skipped file message to mention gitignore feature. - Made all exceptions pickleable. - Fixed #1779: Pylama integration ignores pylama specific isort config overrides. - Fixed #1781: `--from-first` CLI flag shouldn't take any arguments. - Fixed #1792: Sorting literals sometimes ignored when placed on first few lines of file. - Fixed #1777: extend_skip is not honored wit a git submodule when skip_gitignore=true. ### 5.9.2 July 8th 2021 - Improved behavior of `isort --check --atomic` against Cython files. - Fixed #1769: Future imports added below assignments when no other imports present. - Fixed #1772: skip-gitignore will check files not in the git repository. - Fixed #1762: in some cases when skip-gitignore is set, isort fails to skip any files. - Fixed #1767: Encoding issues surfacing when invalid characters set in `__init__.py` files during placement. - Fixed #1771: Improved handling of skips against named streamed in content. ### 5.9.1 June 21st 2021 [hotfix] - Fixed #1758: projects with many files and skip_ignore set can lead to a command-line overload. ### 5.9.0 June 21st 2021 - Improved CLI startup time. - Implemented #1697: Provisional support for PEP 582: skip `__pypackages__` directories by default. - Implemented #1705: More intuitive handling of isort:skip_file comments on streams. - Implemented #1737: Support for using action comments to avoid adding imports to individual files. - Implemented #1750: Ability to customize output format lines. - Implemented #1732: Support for custom sort functions. - Implemented #1722: Improved behavior for running isort in atomic mode over Cython source files. - Fixed (https://github.com/PyCQA/isort/pull/1695): added imports being added to doc string in some cases. - Fixed (https://github.com/PyCQA/isort/pull/1714): in rare cases line continuation combined with tabs can output invalid code. - Fixed (https://github.com/PyCQA/isort/pull/1726): isort ignores reverse_sort when force_sort_within_sections is true. - Fixed #1741: comments in hanging indent modes can lead to invalid code. - Fixed #1744: repeat noqa comments dropped when * import and non * imports exist from the same package. - Fixed #1721: repeat noqa comments on separate from lines with force-single-line set, sometimes get dropped. #### Goal Zero (Tickets related to aspirational goal of achieving 0 regressions for remaining 5.0.0 lifespan): - Implemented #1394: 100% branch coverage (in addition to line coverage) enforced. - Implemented #1751: Strict typing enforcement (turned on mypy strict mode). ### 5.8.0 March 20th 2021 - Fixed #1631: as import comments can in some cases be duplicated. - Fixed #1667: extra newline added with float-to-top, after skip, in some cases. - Fixed #1594: incorrect placement of noqa comments with multiple from imports. - Fixed #1566: in some cases different length limits for dos based line endings. - Implemented #1648: Export MyPY type hints. - Implemented #1641: Identified import statements now return runnable code. - Implemented #1661: Added "wemake" profile. - Implemented #1669: Parallel (`-j`) now defaults to number of CPU cores if no value is provided. - Implemented #1668: Added a safeguard against accidental usage against /. - Implemented #1638 / #1644: Provide a flag `--overwrite-in-place` to ensure same file handle is used after sorting. - Implemented #1684: Added support for extending skips with `--extend-skip` and `--extend-skip-glob`. - Implemented #1688: Auto identification and skipping of some invalid import statements. - Implemented #1645: Ability to reverse the import sorting order. - Implemented #1504: Added ability to push star imports to the top to avoid overriding explicitly defined imports. - Documented #1685: Skip doesn't support plain directory names, but skip_glob does. ### 5.7.0 December 30th 2020 - Fixed #1612: In rare circumstances an extra comma is added after import and before comment. - Fixed #1593: isort encounters bug in Python 3.6.0. - Implemented #1596: Provide ways for extension formatting and file paths to be specified when using streaming input from CLI. - Implemented #1583: Ability to output and diff within a single API call to `isort.file`. - Implemented #1562, #1592 & #1593: Better more useful fatal error messages. - Implemented #1575: Support for automatically fixing mixed indentation of import sections. - Implemented #1582: Added a CLI option for skipping symlinks. - Implemented #1603: Support for disabling float_to_top from the command line. - Implemented #1604: Allow toggling section comments on and off for indented import sections. ### 5.6.4 October 12, 2020 - Fixed #1556: Empty line added between imports that should be skipped. ### 5.6.3 October 11, 2020 - Improved packaging of test files alongside source distribution (see: https://github.com/PyCQA/isort/pull/1555). ### 5.6.2 October 10, 2020 - Fixed #1548: On rare occasions an unecessary empty line can be added when an import is marked as skipped. - Fixed #1542: Bug in VERTICAL_PREFIX_FROM_MODULE_IMPORT wrap mode. - Fixed #1552: Pylama test dependent on source layout. #### Goal Zero: (Tickets related to aspirational goal of achieving 0 regressions for remaining 5.0.0 lifespan): - Zope added to integration test suite - Additional testing of CLI (simulate unseekable streams) ### 5.6.1 [Hotfix] October 8, 2020 - Fixed #1546: Unstable (non-idempotent) behavior with certain src trees. ### 5.6.0 October 7, 2020 - Implemented #1433: Provide helpful feedback in case a custom config file is specified without a configuration. - Implemented #1494: Default to sorting imports within `.pxd` files. - Implemented #1502: Improved float-to-top behavior when there is an existing import section present at top-of-file. - Implemented #1511: Support for easily seeing all files isort will be ran against using `isort . --show-files`. - Implemented #1487: Improved handling of encoding errors. - Improved handling of unsupported configuration option errors (see #1475). - Fixed #1463: Better interactive documentation for future option. - Fixed #1461: Quiet config option not respected by file API in some circumstances. - Fixed #1482: pylama integration is not working correctly out-of-the-box. - Fixed #1492: --check does not work with stdin source. - Fixed #1499: isort gets confused by single line, multi-line style comments when using float-to-top. - Fixed #1525: Some warnings can't be disabled with --quiet. - Fixed #1523: in rare cases isort can ignore direct from import if as import is also on same line. #### Potentially breaking changes: - Implemented #1540: Officially support Python 3.9 stdlib imports by default. - Fixed #1443: Incorrect third vs first party categorization - namespace packages. - Fixed #1486: "Google" profile is not quite Google style. - Fixed "PyCharm" profile to always add 2 lines to be consistent with what PyCharm "Optimize Imports" does. #### Goal Zero: (Tickets related to aspirational goal of achieving 0 regressions for remaining 5.0.0 lifespan): - Implemented #1472: Full testing of stdin CLI Options - Added additional branch coverage. - More projects added to integration test suite. ### 5.5.5 [Hotfix] October 7, 2020 - Fixed #1539: in extremely rare cases isort 5.5.4 introduces syntax error by removing closing paren. ### 5.5.4 [Hotfix] September 29, 2020 - Fixed #1507: in rare cases isort changes the content of multiline strings after a yield statement. - Fixed #1505: Support case where known_SECTION points to a section not listed in sections. ### 5.5.3 [Hotfix] September 20, 2020 - Fixed #1488: in rare cases isort can mangle `yield from` or `raise from` statements. ### 5.5.2 [Hotfix] September 9, 2020 - Fixed #1469: --diff option is ignored when input is from stdin. ### 5.5.1 September 4, 2020 - Fixed #1454: Ensure indented import sections with import heading and a preceding comment don't cause import sorting loops. - Fixed #1453: isort error when float to top on almost empty file. - Fixed #1456 and #1415: noqa comment moved to where flake8 cant see it. - Fixed #1460: .svn missing from default ignore list. ### 5.5.0 September 3, 2020 - Fixed #1398: isort: off comment doesn't work, if it's the top comment in the file. - Fixed #1395: reverse_relative setting doesn't have any effect when combined with force_sort_within_sections. - Fixed #1399: --skip can error in the case of projects that contain recursive symlinks. - Fixed #1389: ensure_newline_before_comments doesn't work if comment is at top of section and sections don't have lines between them. - Fixed #1396: comments in imports with ";" can keep isort from recognizing import line. - Fixed #1380: As imports removed when `combine_star` is set. - Fixed #1382: --float-to-top has no effect if no import is already at the top. - Fixed #1420: isort never settles on module docstring + add import. - Fixed #1421: Error raised when repo contains circular symlinks. - Fixed #1427: noqa comment is moved from star import to constant import. - Fixed #1444 & 1445: Incorrect placement of import additions. - Fixed #1447: isort5 throws error when stdin used on Windows with deprecated args. - Implemented #1397: Added support for specifying config file when using git hook (thanks @diseraluca!). - Implemented #1405: Added support for coloring diff output. - Implemented #1434: New multi-line grid mode without parentheses. #### Goal Zero (Tickets related to aspirational goal of achieving 0 regressions for remaining 5.0.0 lifespan): - Implemented #1392: Extensive profile testing. - Implemented #1393: Proprety based testing applied to code snippets. - Implemented #1391: Create automated integration test that includes full code base of largest OpenSource isort users. #### Potentially breaking changes: - Fixed #1429: --check doesn't print to stderr as the documentation says. This means if you were looking for `ERROR:` messages for files that contain incorrect imports within stdout you will now need to look in stderr. ### 5.4.2 Aug 14, 2020 - Fixed #1383: Known other does not work anymore with .editorconfig. - Fixed: Regression in first known party path expansion. ### 5.4.1 [Hotfix] Aug 13, 2020 - Fixed #1381: --combine-as loses # noqa in different circumstances. ### 5.4.0 Aug 12, 2020 - Implemented #1373: support for length sort only of direct (AKA straight) imports. - Fixed #1321: --combine-as loses # noqa. - Fixed #1375: --dont-order-by-type CLI broken. ### 5.3.2 [Hotfix] Aug 7, 2020 - Fixed incorrect warning code (W503->W0503). ### 5.3.1 Aug 7, 2020 - Improve upgrade warnings to be less noisy and point to error codes for easy interoperability with Visual Studio Code (see: #1363). ### 5.3.0 Aug 4, 2020 - Implemented ability to treat all or select comments as code (issue #1357) - Implemented ability to use different configs for different file extensions (issue #1162) - Implemented ability to specify the types of imports (issue #1181) - Implemented ability to dedup import headings (issue #953) - Added experimental support for sorting literals (issue #1358) - Added experimental support for sorting and deduping groupings of assignments. - Improved handling of deprecated single line variables for usage with Visual Studio Code (issue #1363) - Improved handling of mixed newline forms within same source file. - Improved error handling for known sections. - Improved API consistency, returning a boolean value for all modification API calls to indicate if changes were made. - Fixed #1366: spurious errors when combining skip with --gitignore. - Fixed #1359: --skip-gitignore does not honor ignored symlink #### Internal Development: - Initial hypothesmith powered test to help catch unexpected syntax parsing and output errors (thanks @Zac-HD!) ### 5.2.2 July 30, 2020 - Fixed #1356: return status when arguments are passed in without files or a content stream. ### 5.2.1 July 28, 2020 - Update precommit to default to filtering files that are defined in skip. - Improved relative path detection for `skip` config usage. - Added recursive symbolic link protection. - Implemented #1177: Support for color output using `--color`. - Implemented recursive symlink detection support. ### 5.2.0 July 27, 2020 - Implemented #1335: Official API for diff capturing. - Implemented #1331: Warn when sections don't match up. - Implemented #1261: By popular demand, `filter_files` can now be set in the config option. - Implemented #960: Support for respecting git ignore via "--gitignore" or "skip_gitignore=True". - Implemented #727: Ability to only add imports if existing imports exist. - Implemented #970: Support for custom sharable isort profiles. - Implemented #1214: Added support for git_hook lazy option (Thanks @sztamas!) - Implemented #941: Added an additional `multi_line_output` mode for more compact formatting (Thanks @sztamas!) - Implemented #1020: Option for LOCALFOLDER. - Implemented #1353: Added support for output formatting plugins. - `# isort: split` can now be used at the end of an import line. - Fixed #1339: Extra indent is not preserved when isort:skip is used in nested imports. - Fixed #1348: `--diff` works incorrectly with files that have CRLF line endings. - Improved code repositories usage of pylint tags (#1350). ### 5.1.4 July 19, 2020 - Fixed issue #1333: Use of wrap_length raises an exception about it not being lower or equal to line_length. - Fixed issue #1330: Ensure stdout can be stubbed dynamically for `show_unified_diff` function. ### 5.1.3 July 18, 2020 - Fixed issue #1329: Fix comments duplicated when --fass option is set. ### 5.1.2 July 17, 2020 - Fixed issue #1219 / #1326: Comments not wrapped for long lines - Fixed issue #1156: Bug related to isort:skip usage followed by a multiline comment block ### 5.1.1 July 15, 2020 - Fixed issue #1322: Occasionally two extra newlines before comment with `-n` & `--fss`. - Fixed issue #1189: `--diff` broken when reading from standard input. ### 5.1.0 July 14, 2020 - isort now throws an exception if an invalid settings path is given (issue #1174). - Implemented support for automatic redundant alias removal (issue #1281). - Implemented experimental support for floating all imports to the top of a file (issue #1228) - Fixed #1178: support for semicolons in decorators. - Fixed #1315: Extra newline before comment with -n + --fss. - Fixed #1192: `-k` or `--keep-direct-and-as-imports` option has been deprecated as it is now always on. #### Formatting changes implied: - Fixed #1280: rewrite of as imports changes the behavior of the imports. ### 5.0.9 July 11, 2020 - Fixed #1301: Import headings in nested sections leads to check errors ### 5.0.8 July 11, 2020 - Fixed #1277 & #1278: New line detection issues on Windows. - Fixed #1294: Fix bundled git hook. ### 5.0.7 July 9, 2020 - Fixed #1306: unexpected --diff behavior. - Fixed #1279: Fixed NOQA comment regression. ### 5.0.6 July 8, 2020 - Fixed #1302: comments and --trailing-comma can generate invalid code. - Fixed #1293: extra new line in indented imports, when immediately followed by a comment. - Fixed #1304: isort 5 no longer recognises `sre_parse` as a stdlib module. - Fixed #1300: add_imports moves comments following import section. - Fixed #1276: Fix a bug that creates only one line after triple quotes. ### 5.0.5 July 7, 2020 - Fixed #1285: packaging issue with bundling tests via poetry. - Fixed #1284: Regression when sorting `.pyi` files from CLI using black profile. - Fixed #1275 & #1283: Blank line after docstring removed. - Fixed #1298: CLI Help out of date with isort 5. - Fixed #1290: Unecessary blank lines above nested imports when import comments turned on. - Fixed #1297: Usage of `--add-imports` alongside `--check` is broken. - Fixed #1289: Stream usage no longer auto picking up config file from current working directory. - Fixed #1296: Force_single_line setting removes immediately following comment line. - Fixed #1295: `ensure_newline_before_comments` doesnt work with `force_sort_within_sections`. - Setting not_skip will no longer immediately fail but instead give user a warning and direct to upgrade docs. ### 5.0.4 July 6, 2020 - Fixed #1264: a regression with comment handling and `force_sort_within_sections` config option - Added warning for deprecated CLI flags and linked to upgrade guide. ### 5.0.3 - July 4, 2020 - Fixed setup.py command incorrectly passing check=True as a configuration parameter (see: https://github.com/pycqa/isort/issues/1258) - Fixed missing patch version - Fixed issue #1253: Atomic fails when passed in not readable output stream ### 5.0.2 - July 4, 2020 - Ensured black profile was complete, adding missing line_length definition. ### 5.0.1 - July 4, 2020 - Fixed a runtime error in a vendored dependency (toml). ### 5.0.0 Penny - July 4, 2020 **Breaking changes:** - isort now requires Python 3.6+ to run but continues to support formatting on ALL versions of python including Python 2 code. - isort deprecates official support for Python 3.4, removing modules only in this release from known_standard_library: - user - Config files are no longer composed on-top of each-other. Instead the first config file found is used. - Since there is no longer composition negative form settings (such as --dont-skip or it's config file variant `not_skip`) are no longer required and have been removed. - Two-letter shortened setting names (like `ac` for `atomic`) now require two dashes to avoid ambiguity: `--ac`. - For consistency with other tools `-v` now is shorthand for verbose and `-V` is shorthand for version. See Issue: #1067. - `length_sort_{section_name}` config usage has been deprecated. Instead `length_sort_sections` list can be used to specify a list of sections that need to be length sorted. - `safety_excludes` and `unsafe` have been deprecated - Config now includes as default full set of safety directories defined by safety excludes. - `--recursive` option has been removed. Directories passed in are now automatically sorted recursive. - `--apply` option has been removed as it is the default behaviour. - isort now does nothing, beyond giving instructions and exiting status code 0, when ran with no arguments. - a new `--interactive` flag has been added to enable the old style behaviour. - isort now works on contiguous sections of imports, instead of one whole file at a time. - ~~isort now formats all nested "as" imports in the "from" form. `import x.y as a` becomes `from x import y as a`.~~ NOTE: This was undone in version 5.1.0 due to feedback it caused issues with some project conventions. - `keep_direct_and_as_imports` option now defaults to `True`. - `appdirs` is no longer supported. Unless manually specified, config should be project config only. - `toml` is now installed as a vendorized module, meaning pyproject.toml based config is always supported. - Completely new Python API, old version is removed and no longer accessible. - New module placement logic and module fully replaces old finders. Old approach is still available via `--old-finders`. Internal: - isort now utilizes mypy and typing to filter out typing related issues before deployment. - isort now utilizes black internally to ensure more consistent formatting. - profile support for common project types (black, django, google, etc) - Much much more. There is some difficulty in fully capturing the extent of changes in this release - just because of how all encompassing the release is. See: [Github Issues](https://github.com/pycqa/isort/issues?q=is%3Aissue+is%3Aclosed) for more. ### 4.3.21 - June 25, 2019 - hot fix release - Fixed issue #957 - Long aliases and use_parentheses generates invalid syntax ### 4.3.20 - May 14, 2019 - hot fix release - Fixed issue #948 - Pipe redirection broken on Python2.7 ### 4.3.19 - May 12, 2019 - hot fix release - Fixed issue #942 - correctly handle pyi (Python Template Files) to match `black` output ### 4.3.18 - May 1, 2019 - hot fix release - Fixed an issue with parsing files that contain unicode characters in Python 2 - Fixed issue #924 - Pulling in pip internals causes depreciation warning - Fixed issue #938 - Providing a way to filter explicitly passed in files via configuration settings (`--filter-files`) - Improved interoperability with toml configuration files ### 4.3.17 - April 7, 2019 - hot fix release - Fixed issue #905 & #919: Import section headers behaving strangely ### 4.3.16 - March 23, 2019 - hot fix release - Fixed issue #909 - skip and skip-glob are not enforced when using settings-path. - Fixed issue #907 - appdirs optional requirement does not correctly specify version - Fixed issue #902 - Too broad warning about missing toml package - Fixed issue #778 - remove `user` from known standard library as it's no longer in any supported Python version. ### 4.3.15 - March 10, 2019 - hot fix release - Fixed a regression with handling streaming input from pipes (Issue #895) - Fixed handling of \x0c whitespace character (Issue #811) - Improved CLI documentation ### 4.3.14 - March 9, 2019 - hot fix release - Fixed a regression with */directory/*.py style patterns ### 4.3.13 - March 8, 2019 - hot fix release - Fixed the inability to accurately determine import section when a mix of conda and virtual environments are used. - Fixed some output being printed even when --quiet mode is enabled. - Fixed issue #890 interoperability with PyCharm by allowing case sensitive non type grouped sorting. - Fixed issue #889 under some circumstances isort will incorrectly add a new line at the beginning of a file. - Fixed issue #885 many files not being skipped according to set skip settings. - Fixed issue #842 streaming encoding improvements. ### 4.3.12 - March 6, 2019 - hot fix release - Fix error caused when virtual environment not detected ### 4.3.11 - March 6, 2019 - hot fix release - Fixed issue #876: confused by symlinks pointing to virtualenv gives FIRSTPARTY not THIRDPARTY - Fixed issue #873: current version skips every file on travis - Additional caching to reduce performance regression introduced in 4.3.5 ### 4.3.10 - March 2, 2019 - hot fix release - Fixed Windows incompatibilities (Issue #835) - Fixed relative import sorting bug (Issue #417) - Fixed "no_lines_before" to also be respected from previous empty sections. - Fixed slow-down introduced by finders mechanism by adding a LRU cache (issue #848) - Fixed issue #842 default encoding not-set in Python2 - Restored Windows automated testing - Added Mac automated testing ### 4.3.9 - February 25, 2019 - hot fix release - Fixed a bug that led to an incompatibility with black: #831 ### 4.3.8 - February 25, 2019 - hot fix release - Fixed a bug that led to the recursive option not always been available from the command line. ### 4.3.7 - February 25, 2019 - hot fix release - Expands the finder failsafe to occur on the creation of the finder objects. ### 4.3.6 - February 24, 2019 - hot fix release - Fixes a fatal error that occurs if a single finder throws an exception. Important as we add more finders that utilize third party libraries. ### 4.3.5 - February 24, 2019 - last Python 2.7 Maintenance Release This is the final Python 2.x release of isort, and includes the following major changes: Potentially Interface Breaking: - The `-r` option for removing imports has been renamed `-rm` to avoid accidental deletions and confusion with the `-rc` recursive option. - `__init__.py` has been removed from the default ignore list. The default ignore list is now empty - with all items needing to be explicitly ignored. - Isort will now by default ignore .tox / venv folders in an effort to be "safe". You can disable this behaviour by setting the "--unsafe" flag, this is separate from any skip or not skip rules you may have in place. - Isort now allows for files missing closing newlines in whitespace check - `distutils` support has been removed to simplify setup.py New: - Official Python 3.7 Compatibility. - Support for using requirements files to auto determine third-paty section if pipreqs & requirementslib are installed. - Added support for using pyproject.toml if toml is installed. - Added support for XDG_HOME if appdirs is installed. - An option has been added to enable ignoring trailing comments ('ignore_comments') defaulting to False. - Added support to enable line length sorting for only specific sections - Added a `correctly_sorted` property on the SortsImport to enable more intuitive programmatic checking. Fixes: - Improved black compatibility. - Isort will now detect files in the CWD as first-party. - Fixed several cases where '-ns' or 'not_skip' was being incorrectly ignored. - Fixed sorting of relative path imports ('.', '..', '...', etc). - Fixed bugs caused by a failure to maintain order when loading iterables from config files. - Correctly handle CPython compiled imports and others that need EXT_SUFFIX to correctly identify. - Fixed handling of Symbolic Links to follow them when walking the path. - Fixed handling of relative known_paths. - Fixed lack of access to all wrap modes from the CLI. - Fixed handling of FIFO files. - Fixed a bug that could result in multiple imports being inserted on the same line. ### 4.3.4 - February 12, 2018 - hotfix release - Fixed issue #671: isort is corrupting CRLF files ### 4.3.3 - Feburary 5, 2018 - hotfix release - Fixed issue #665: Tabs turned into single spaces ### 4.3.2 - Feburary 4, 2018 - hotfix release - Fixed issue #651: Add imports option is broken - Fixed issue #662: An error generated by rewriting `.imports` to `. imoprts` ### 4.3.1 - Feburary 2, 2018 - hotfix release - Fixed setup.py errors - Fixed issue #654: Trailing comma count error - Fixed issue #650: Wrong error message displayed ### 4.3.0 - January 31, 2018 - Fixed #557: `force_alphabetical_sort` and `force_sort_within_sections` can now be utilized together without extra new lines - Fix case-sensitive path existence check in Mac OS X - Added `--no-lines-before` for more granular control over section output - Fixed #493: Unwanted conversion to Windows line endings - Fixed #590: Import `as` mucks with alphabetical sorting - Implemented `--version-number` to retrieve just the version number without the isort logo - Breaking changes - Python 2.7+ only (dropped 2.6) allowing various code simplifications and improvements. ### 4.2.15 - June 6, 2017 - hotfix release IMPORTANT NOTE: This will be the last release with Python 2.6 support, subsequent releases will be 2.7+ only - Fixed certain one line imports not being successfully wrapped ### 4.2.14 - June 5, 2017 - hotfix release - Fixed #559 & #565: Added missing standard library imports ### 4.2.13 - June 2, 2017 - hotfix release - Fixed #553: Check only and --diff now work together again ### 4.2.12 - June 1, 2017 - hotfix release - Fixed wheel distribution bug ### 4.2.11 - June 1, 2017 - hotfix release - Fixed #546: Can't select y/n/c after latest update - Fixed #545: Incorrectly moves __future__ imports above encoding comments ### 4.2.9 - June 1, 2017 - hotfix release - Fixed #428: Check only modifies sorting - Fixed #540: Not correctly identifying stdlib modules ### 4.2.8 - May 31, 2017 - Added `--virtual-env` switch command line option - Added --enforce-whitespace option to go along with --check-only for more exact checks (issue #423) - Fixed imports with a tailing '\' and no space in-between getting removed (issue #425) - Fixed issue #299: long lines occasionally not wrapped - Fixed issue #432: No longer add import inside class when class starts at top of file after encoding comment - Fixed issue #440: Added missing `--use-parentheses` option to command line tool and documentation - Fixed issue #496: import* imports now get successfully identified and reformatted instead of deleted - Fixed issue #491: Non ending parentheses withing single line comments no longer cause formatting issues - Fixed issue #471: Imports that wrap the maximum line length and contain comments on the last line are no longer rendered incorrectly - Fixed issue #436: Force sort within section no longer rearranges comments - Fixed issue #473: Force_to_top and force_sort_within_sections now work together - Fixed issue #484 & #472: Consistent output with imports of same spelling but different case - Fixed issue #433: No longer incorrectly add an extra new-line when comment between imports and function definition - Fixed issue #419: Path specification for skipped paths is not Unix/Windows inter-operable. Breaking Changes: - Fixed issue #511: All command line options with an underscore, have had the underscore replaced with a dash for consistency. This effects: multi-line, add-import, remove-import, force-adds, --force-single-line-imports, and length-sort. - Replaced the `--enforce-whitespace` option with `--ignore-whitespace` to restore original behavior of strict whitespace by default ### 4.2.5 - Fixed an issue that caused modules to inccorectly be matched as thirdparty when they simply had `src` in the leading path, even if they weren't withing $VIRTUALENV/src #414 ### 4.2.4 - Fixed an issue that caused module that contained functions before doc strings, to incorrectly place imports - Fixed regression in how `force_alphabetical_sort` was being interpretted (issue #409) - Fixed stray print statement printing skipped files (issue #411) - Added option for forcing imports into a single bucket: `no_sections` - Added option for new lines between import types (from, straight): `lines_between_sections` ### 4.2.3 - Fixed a large number of priority bugs - bug fix only release ### 4.2.2 - Give an error message when isort is unable to determine where to place a module - Allow imports to be sorted by module, independent of import_type, when `force_sort_within_sections` option is set - Fixed an issue that caused Python files with 2 top comments not to be sorted ### 4.2.1 - Hot fix release to fix code error when skipping globs ### 4.2.0 - Added option "NOQA" Do not wrap lines, but add a noqa statement at the end - Added support for running isort recursively, simply with a standalone `isort` command - Added support to run isort library as a module - Added compatibility for Python 3.5 - Fixed performance issue (#338) when running on project with lots of skipped directories - Fixed issue #328: extra new can occasionally occur when using alphabetical-only sort - Fixed custom sections parsing from config file (unicode string -> list) - Updated pylama extension to the correct entry point - Skip files even when file_contents is provided if they are explicitly in skip list - Removed always showing isort banner, keeping it for when the version is requested, verbose is used, or show_logo setting is set. ### 4.1.2 - Fixed issue #323: Accidental default configuration change introduced ### 4.1.1 - Added support for partial file match skips (thanks to @Amwam) - Added support for --quiet option to only show errors when running isort - Fixed issue #316: isort added new lines incorrectly when a top-of line comment is present ### 4.1.0 - Started keeping a log of all changes between releases - Added the isort logo to the command line interface - Added example usage gif to README - Implemented issue #292: skip setting now supports glob patterns - Implemented issue #271: Add option to sort imports purely alphabetically - Implemented issue #301: Readme is now natively in RST format, making it easier for Python tooling to pick up - Implemented pylama isort extension - Fixed issue #260: # encoding lines at the top of the file are now correctly supported - Fixed issue #284: Sticky comments above first import are now supported - Fixed issue #310: Ensure comments don't get duplicated when reformatting imports - Fixed issue #289: Sections order not being respected - Fixed issue #296: Made it more clear how to set arguments more then once ### 4.0.0 - Removed all external dependencies isort-6.0.1/Dockerfile0000644000000000000000000000123013615410400011564 0ustar00FROM python:3.13 WORKDIR /isort COPY pyproject.toml uv.lock /isort/ # Install uv COPY --from=ghcr.io/astral-sh/uv:0.6.0 /uv /uvx /bin/ # Setup as minimal a stub project as possible, simply to allow caching base dependencies # between builds. # # If error is encountered in these steps, can safely be removed locally. RUN mkdir -p /isort/isort RUN mkdir -p /isort/tests RUN touch /isort/isort/__init__.py RUN touch /isort/tests/__init__.py RUN touch /isort/README.md COPY . /isort RUN SETUPTOOLS_SCM_PRETEND_VERSION=0.0.0 uv sync --all-extras --frozen # Install latest code for actual project RUN rm -rf /isort # Run full test suite CMD /isort/scripts/test.sh isort-6.0.1/example.gif0000644000000000000000000023762013615410400011732 0ustar00GIF89a         # !$ (8 !!%$%!!"%%&!($*&,"(%(',(.(*)-,. (()0,2*1-1-5021546283<595<9=$'00"//# )((1.-20/988N:@=A>D8?A""h*G)AE8@B"hhB<;XXDC6FFFGORGPSPNLSPOXXX[eg`]\c`_nmm--88;;UUUUUUCCKKOOPPRRSSTTUU**9˨VVEֱNľ½9! NETSCAPE2.0!3, H*\Ȱႇ#J3j8Ǐ )\Id R\r bʔY-rl狟@JѣHX#?J Bj!Xf•`"Kٳg]˶*jTBݻx˷,r LanNY̸Ǎњ=B˘ KϠC{֊ӨS>-UװcAms߾cN8ȓ+_|sУKNuسkߎ7O3\/ )ʗ%_ ,L3XN;ԓOA5HPI%TSOUTUWCl(Yh"\,x؋(c[؈!fcf棏 ڐCZlHfےE9/]GB4(3ʄ((NVVb/0-"x*SRuFрxqUw =)ÚctGqeтu=DЌ&GMj|KI 4\t-tk&9ON*T+H0WLET`90ꊲLkY[c#/yNpߊycBZ{x'͎$ iH 9+\v&ȧ Mf:@3C(鉣)$HMRYAɲ--IJXjV}U 7 GeYϢaFzT)\!<|H"SM/5lB-Ȓ D]SjF*uw6b* ЧNCQ%Tqy1c]W D+21iq\wJ!+^:9Ok+@hdbљSmLc6[ xKj%iL^]g KF´#l)VY 0s% {;̐`=Cm^}KrNz2g"d&ߝbuͱ@V^LM~XMr&ozrLYyI$ aL2h>36/M2,\(`^ bԯ%匮9]hӍt'MJ[ҘδcܠF{NV|)RWj?j[g-H _Ђw^@bVB {cЎMj[ζn{ǽmzNQv𶇼Mz=~xAO ;\A[ϸ7{ GNK\wW =M8 $E.NHOҗ;PԧNXϺ{{^F0AvbhO1qcp;ܛAf8΀ޡhHҠ5Aj\6xm8ވ7Aʇ86qx<9F?r7WotOgugwώv;A/7~o(Mӧ=m7G><_|=qO_=_ҏ>8yyWy x xPx x' }w Al "8$X#x p &,؂.0284 :<8 @@xtZu \v]'vbWvdvkvo ugwxw}w(Ѐ wyy8Wz{{{~w|gmn4W}p}ط}Hq*r߷o4nWm~~wu8׆k(i(g ؀`XxY WwTvhGv% "X ʸX ,( ` 0 ` 5ڸ؍7ȃ⨃BxDXXwJL N8ve'SvqWww[؅XbxdXfX(zHu{(|}8Vvrp׈ }6Vv藉}ȉ8sh iY 9W^X[ uwnv0p @ p 0 p + p q ؖnpi88X爎騎JPvlvsx} I;Ix iwzȉ|vnҧ`} Iq"9އg'inצ-~/1x k=ɀ([Xw׋Kɔ a!QSk_QQNQ& ~8@ YٍHuyxiuzHؗ~yvJI9XxyIɇ~|hnop)'+)jp(0oG|)|{4iIט@ٜ7tmLٔèRI _@)QI0 0 pr:tjhHڎ HT zw  zsؐ{GgInHsp(ppWv :jm|lj93Yoxɩ𤅇ϹIiWvuE\ʝ^J Y $X p@ Xyxv|jt~ʗIjiVhʠ Jx꘏mXz9{ Ymv @}@ @p@poWZ(i<,.:2977YK*M Qx7IYgך ؝P_eJ r;(xZz yLHz;x_ȨװWjz;Wˡ !*& m!+P6op/7p .@:gFz;z~=~}XZLk˪ A霺hUW Y[vغ]c g; ˾оP ՐlI{r9 x}}Hwh ;: Jy|( 0@`ƒP`0o2L@ @ &2go.K 6pÂ` o+-Q0 mp0':D F{FHᠬLJD);ًP(v˵НYK"x ` 0ɓ@ɘ p ɞl˟(\ [xɸʱg`A<@F PK|`@ ð A<}M 0o Ë@<| p Ņ0 1˻>? BƷWH8ٴy,R[|̽\WP Ҫ0^kIf0 Ӑ =>m { 9]F}HJLNPI PV}V ^]] Pfmֺֺun p L( 0 vvŀ ɰr7 0؂W؅g ֠xט -ٚ' rXx{*̹ |:p:ZKynP@p 6 n`n v @ 젣m`*0м~ |ٶG׆場(: ې؅W؂7p w{ Ȁv= ẗ́p]Ȳp ~ 26}~Ζ"≐ *,.02>4^. 7 ܟDgGط~Y8\(ʘyHߓkޝ |K|Gڀ v M VP P}@8|nPpn|6m m m.|.K 7k,o +ǡGv|NDŽC̀ǠKvbu EN>Qe[.̮%`>^~/: <@AFXuHnvow劻TMٕ]ka.}p|̗e\);*Ҧsp=֝`| ̓@ `qiK zH҈7^ԩ ގE ~S9ӭXǮ⥛ b?PP ؞jl;C(Hބ^KNw< WykٽS t7א 0 p  |ڌ~   -, 'Ϝ ӭ|`P @ `M{]??A/{H?[H붎PuE nL ah` OxZURF5liZHݻvu hw?w&1Y@s;l0k/‹r+:, ,ڪe:*c**bZ * GdMFa&Q~H0ʤAHHcF2J,rK.A"\%|&nI'JŦX E*Dg>Ci6D+ ኋB /c0 CP pӌ~qG}@ǝ|@wUVXu'GxO~t\5yt4YWU{hTYOU|qWP4,K#I԰GkTEI. 1 @sB1rq{S(#֑ǁ!b386d&cdJ6dSVySH Z2L4\36{z΢eΪS+>4 e-Cz7wkלuKWLͽN ?ӎumvmN{ޏľ ݯnlzymiA8DMPA..ɺk-{˶|@uWꧏEOB0`QNa 抢]lF@F0$sJX;ٝv7c 5wB{dq%DJC^C!j6k >Og#}K8 ~5aVQ0POR|9B7F8BKD 28 r'C8'ىhޞVBKynZAopӣ^&2SؐIP3<߰wI/Wb/-.Z$EDbL30=YR$Sdf3LhFSӤf5yMlfSL@TMp '+\qNtxELhNx³NpqO|B} EJ0 "%CbC BC 4,J R_(6.t!ny =JV1,P&DJ.K Fp+^𕯐rn(6QjXtaD! 9t MBbac/|@~"FdrSkek[Vbӛ⤫*iNu敝g<9Oa|πTUBU>4MXTnjP6B6dJdӮԥ2Քj3u4:mh}8uج0TPOCbtauGXB'P]Unwֹ5wͫ^ ,aխ2TTVhQwّv/)RҕejI)OmStmF\7u,V܀~atzXnm|cs7&9Was|M/-ޱWwh|:m~vt#I*pi|f4R")\[0 ꆋzT~8TIlUo`e`wWxXl(hHGZғt-}iLgZӛt=iP[z*LMG 3]>gDA ~WAK"˒E2^~d$O:6zM%0hG~PW,![ϋ<z"a JsjZ2QP[wo~#FIxVIPz[(*4VFCCӞ&l}2m`i+g9SWTgKYz۵|@HV7n=3wK4ԭ>K,ߍ3-RcY&JXv~Sj=BAOx4d5H`6ȿ<`k%zy 7(׆1lšz_Pqˊ[n0<^~]FD/xщ((c_@C. =u { ~UI_H?g&~B]xƻ;nϋ^pDs}ۑ8s̛1B< =Y;jӻի42X \H7'%٫LL'FpJxHhJ(p'4M>#>~BtBG+ Q;05Tp>V23YڱY5;5^5_cC? 9c?s?'  >~>~KAO #EG#UQc%lB'BU™„b.0,"+A\8-;C;Gr,Ǚ0pCmùl?"C 4R{{DHl8C DX|@Qh/p1AMsB/KXJ NC2x/EZ4p.:3p=Q '(NHGC3A'0| Hx*'pKA$KAQESIPԴ4TIH B@F8Wh=@2*2y'% &kªB.c2ڊz¬Ҳ-ԬS;UG;S 9S;{l4 6M*%>#q27@ӭA "'+'` S'13TO2A'NPX(H<4U'@$䤽 -OX]?U݄,/U4]]N'x'h?VjMk/\U`ApNZ}iO4fF(U4am$JTN^TQp1`e-ni"՝T1r2?`'ms/@'v:*Tz - 79/* S)33MS5/6 TxSSS2=ٛYY(A%ԥ2;STTFuTAk. I'KLM=T&PLOZUBhYev'#1[O׶]N>/ s=D(`4('Nz۷F@.suVM<$ONPhr܇MP'`ֻ}O1 5UO\|}]]Lej2XU #IUASEU>VXWh'(52,R|R. Y(-YӅ,jD}٠ٟٞ}__ڡ-TA4BDEeTGިBڪWZtTrZq:l=[Mμ\}^Pe'OrK MOMHXKaka\z\B\5F>]10l\vam5,έ]-|@]MAS(oBUWqUh=b^ڍ]YzECٔUY2_AͲ]䟽F~dMZ-=33Ud&G;] ,Je-`` SH [ԕ[#]#AUaM]2\3 K\˕]ܶmE%=UmvPH.&ӠHLHb[KRP`KmF(Ih3f~fP(f$F}|FlwG(4eo*P@ m2Wv*X5I2.ґS?;b(_AdhP+d,di> -=__dNdd}ZݙUTڬhWUpfeR1Hx'f b{VZ\A8/N]D%ܮt3HMln(h&x2J8lMV!&gj='tQmᇜLh۵FHkPxk'┌FWL8mvl4thd38PKPCxIO1ve9&'=ؑ =c>c?Fn醺)䠞(nYi.o_.dndNjenWUv`j'~<+x@NHp_poppp p p p p pg#F@m _&##;U+;4QcqQqrÊ8?"'>r$"_rBq(qq_޼y{1q/aBL+:os7s8s9s:OR ?SXH_8.qq+L*>)?(r' grK&tJtN)oE_,r-oD.s2' S 44EcEc:u\u]u^sPS35?/8sA'B~l8D#P>*7!OtNvtmvojF7E<Zģ35r/0ȁlT03PKp^wx6u`;Tvb@?vgw\vLt,h˵poxxO*h7`aeMTNwwVwzXwy~_s'xyz7x`?w_̉GQ;hvyO~tcxrݜzG~\yoyxw1wuX{{S{{||/|?|O|_|o||ȏ|&SjC5^ jn~2 ^O eo}_ Տ2"~+RA`TZ 7kzgĿ{S~~~~~~~~/?O_og.,h „ 2l!Ĉ'Rh"ƌ7rQ",Xpݩ*3J%̘2gҬi&Μ:w8Rdɓ)XS"JǠ ' IehS$F+ذbǒ-k,Z?CE9P +#FyZ0 f"$*A'\zM1Ȓ'Sn^A*B<NM/"qزgӮme ލxppȱu:r#g͜)M"ʼn /M"З l<rrËܳA"4WkQfzEW]! NDSmz!!Ɩ[I $x!pٱ A_q#|}D]Dbfxv8IY_7sq_RHsWȁWdВAFkI.$l,DN}'D&r`*E&) }U!"DUc*T@G(!W{NF|ǩ*:\A}@EH&jݥF)(*,"Q0R*]N j@*Ttik~lh]FW (gV[+` I*+lK rpy"!A20K.(uF-ꨶv+Ƿ+™~nIX+2 r K H஻믉P9<1M;tL!Q@@]'2*se#;L@xq4ϋ!^n=P+ii[Hp6(' Йם9A}9kSOm5#@#ȑz;e  &Xy r]|g:;~: VXU M&bA`m9{SOT9%V*>NR8Q<37!H&$:iJ( R6|V rR&"DQ@w%RVdZ.(^"E-Bs] #ӨFʌf(9[|=%vACGC2"1GRz1EKr`Ĥر OT(% .6~.90C2Ab^)a$c-Gy\.$@ZHLfЅTqˈ)qD0iˎ8 kR7yifs@@r@PR<(2a.,|<POkJShΟ&=iE PdrIQ41ե@ryS[&8n ۜgGifLFJԆ VBTD.eD K1hYLcU Hej=CQi"@!P׽D|VWT̩.ϊص U!PfS;JOm!+f t-(3@-fZ9'±؄,\ Xfs{vB +T=mjuԥ !U*\=JMiB 4-vفԷ_ehBJZD@^\˭=dԅ6%g<ـz׫/ ,g* /[ph+L3J| *{S&&g= &%kF!76d9CY%D^̑F@7>2%sct:kjxSΥeC*,v2a| ܜf5le,ö́J%fv{PA3YxC,9vyo\:΄ύ֖sj)U>wӾA-;2bشU]7Qzʽ5xFTAvZ^fbH=Kdl6؂*r"F/Ӻf*6bo@IlUp.8q}zĮ 8=V-syk[6x Top n t/[4mA+ jͣC@<77+'8ͥ.R]@ωgԅg<*a: $.;N~؊/>ҿ_W??{{?o?H_w`  DK D ̟%fE`Ξ vDh " 쁠D I N G8{HAG}Gr,|MG$BIŠE i\P dɖMAI NAFDA\(!r@̬( BD@#u.RDRa ˽`Z@ #"N8 @N،! t !ј"/*ԍMތ́Ԉ񴇊 B!^ ("6Da*a NpN+6} (aJ6J6r`7!C8EHDDEvmddHqGl$I$KJH֣J dK$Dfd=~JҤNKF NN%YdO@N RQ#&RFMUF6"TJVUVU"%PnXDWWf@XZDAUd*eE%]~D[eD>\%_]Ze\e_&Ee d9%a6D&bjb"K:A?d^QaN0S@źhŐefffN`\h(H橔& A$a\(D v)!affbX̦AMxbjtRq6rjf9oGRq!tcxTudǒXw GvLW Ng zy aʂ$BbxXυ rgw]er|~aHI|KHG ēLbV b( @#\㚴,ΜɝɞTphar(x.⾀MMXT~ +ǫK Aa` 4W$MWTU<bҕF$x^pdbP" VʨLD%KR, t N°!A}n(zh9(jL1F뤌"s^jfͼl"i  , *ʪjЀ*0͉ڍ6`4W˰M+t0Rb|c.c!ANu"i@4 UHP@pk]iQ뇊+9240FL Hqi+9xc,U PPfy$R ^l;ECe!0)m[V%ުNrNOR0Y~kq%PDM؎-fVi* mw֭^j-mj8:*-2%߈aSN+ƫ^!h2rIab*i4C;.ƻ{f{_o3{޿nWP||:7'0DDc(C跆&C+7DտFG+Bx0i8΄5svD ?A 0sp=Īr>K~ 'i'@[u!^_ @O/I/K 4>|AQA#d @("B,"A5q E rRȏ4VhHFI<3H 9v:Y3fD'%*T(I#B_%:+D">BGPSjuiӧ $rc53{ j}hS@JEFS aL7u$[z !'P prRc jZR|T]_}tPdkuZw xүrϥI6ܜh/B6|gS- @CA_b.VCn{E(e]F9,ݎVc=VW, f,zڞBI_M<=rpZGv[.ڔVvBl%3W r͕0]CI,`v<)[_b\9@`C gw]dl ďЇ!G%d1# a?? ꁉf#nSm`!  r@@A'5c Q qLdU!`df#[$fhfYb Hs%b{l*Ӛ$7eD.{ j2PV'|$=\'UPSTg˳3 hK(!wAhEʬDU4 9*MQ%10@A A?8%*$ r <#NM?MqJFx!J)B10iS>~D,\@i"&*&K]MX{cV yj:מƮkVje-jv$+`AErE,Y4֭yf'XYh Kv-,X]YF+Al*6I-k#[ۺVGJj ۈHkUZ˸_RRh}ὤx[匎 ;oD;_׾o~֗} A0n] 1RkW%T 08(#.&qaq~7 }5qIVd'?Q^͍S #oRe/a * Vrf7q鼜3Yg?ЁլgAщVh?yv)]iK_Q&3iOԡ@6- CթVYRձi]k?k[vq][VF[׼]mk_>mo&-ns鶳mw[}vȞ6oηv tm?DT)^?3<8w.Z!y1qpѕn srsᴚd5zÓseַ*O"P^(I)|T)KsZWdiѿ8'?bR U$B Pj#xJqPV F08L†LkqEo0rpaP " -M_U.  o`i f/ wl wz0\ K C/ ">(~Bn&!++ Q" q` 3 o"DKNC.* 1BH|"'[ou"hHb>0 op[POV#GgjoejQC"JoEgJVOu/"$koQoƏK/,"+cKQ=o&o00Ы6nO"o%J I[*#?.2r#cA%o$M#SR&k#]gR'gnR#_r'#{%9$)(Y(2)Rr2'*?1(+0+Y),0,1,, r$i@-2 ./}/T-0;%0002/201's,S2)S3o2(s3C:J33S4SSH4#֌P5cS:Z4Iq w l'ʜɂ,4Te3 3/k4&0ɲC3'ɀp5h KCË:s딓\63а34HSs>K ?A,K&C"QDD֓x:PbIJ DL,q#H1Pqi|*O Ɍ`]{PqP7oZTY Rդ>ZU<R1G/Ք1?Ss,V%p5Da6/8ܕ$uV-cus_CW_U`q VYsnÐegzx< qR)ܱHJ䑣fTXqOIq~.0diuVkDea1?g6`Fj*@s6 ,6VU@j$2*!f$rDP@Kppp#JKVO6^+unʗvVfdpu7.Snng$Qvo7h@w_`ne|,E wwyy#v z7x_gxQS{ܸWnW||9_}Է<]}{~w_K|׀g_c 뗀؁-W@y؂8/UJ/؃?-7x;KBx*G؄W8Bx.5*g\`XiX'-/g@MIxz&cX鬇%8lX 6X5]{x4drC+Ȏ#TɬÈsˋ]@UH3H*q9ylR3yݘZо09Yu[90xf,J'$ YyY8&lI2&G'ؒ78&"&6tc(*t@bG)6<4G', FC-|e+r4Al"&/py/l9:!=C,UYyؕ11ίHCKtJ8ExԁFpDG G~Lz"5DoK֙tH|S珜3T](F.jD!EFPhBD9Z8Jfb/3aY UokRiq guhz^'"$IG[mu2"{zYYˏ`_V ,ZPjIbmvGxغܺn!fY+#UPfj56{-ϓoii/;j!tdi$¶!':Qk`_usMKor) jI>ש`Lq [0;%L_αxXAa,{#ɫz[({/ٽ,qū{'׻ήs?"|& jzpsjL5uâ ׃ݣ=Cڮ}hדc_X[A )]DZ }^6᭑;"6R;{h?5}֒KL+"iC;V{Kʶ=j,u4M3]Vogᑻ˹m都ºQ;T'[CO|-{ף>{Abw>M>;iqõLr"(=qIWZ"Ug70?5 7* ue!l?" Yaj0R p:Lg&{M3^J۟߿)O"80… :|1ĉ+Z1ƍ;z2ȑ$K<2JZnS A+kڼ3Ν<{ 4Г._XpҥL:} 5ԩTj ̪\z 6رd)jȚUfҲlۺ} 7ܸgfPKs޽| ]k>8@Eɔ+[͜;{6A>:꒢IU0ٴk>:9x֤Hċ\WHYԫ[.r 1˯Ծ<ۻBۿnmG_`ghGA >a-\IaE@nb"6աb*֔-22HcG/\5c ] cFʈ#vlG> %IGn\Zn9sA'fwfr&͉gM ܩg 9hV(h.d=:i&V鐎"i䐗:jU k]z*ފkP~jkz l$@*8yln,ˎPVܴ~KbhsE7ꮫиfkn뺻&/:/Jp¹ ?|,CL!, 8@A *XÇ2Hq3jtЯ )I Re0;xI͛6O٢O. HҸ)PJիAʵ!`KlG$hӢȶ*pʝ -*x˷o L~+^w0ǐ#K˘3k޼n#CMَDR^ͺj!mȞM۲}ͻ8jNkXμ0N}سν{ ࿃OyҫWox Fbō񃔀J-K5M;PB%QJ- QEEUUWuhUV^8i$։iE׊,2{&48Nxg@\ihE$ڒLvnPF9UieoW%= dih^| '}ty_~ RHS PPTZ8pa!r%V$"d棏5ZkM0W}=ؚ-com;[ sݙD ȷ͚.A%+ |b.i' z;zOԅCjjvZcюG*S<9xcQG9I,E]{0S͸G)r" Ab!-} u&ҕ^I:NB PVY`D)A^*Q[/ep Xi L(XN x3ykk!`zx# d wH>';mc 'Nb$ŤI*b̊R[G$ !WVde*A㠑tCR91}z 0>Sd!CY&Adf OGdnzs1'=pv`fl%;ɯe ɥ$ @G;N2u@φ:si<+SF7юΜS'- R-(-jD3EӚ&8ͩNw}>`?&!PZP>Y JOyRKTfMͣXͪV*ta"-g"lZU Ә_LaMJWJT1R&zj9UϪd'KYam$/;+Qu}hM6%`ֺlgK[ $f>vnB⭢8P:lfgXEw.GlJK6zoU4Mz}^sǝ$!~u'II LX!;]q򹖽.YLaM¡v7<|cmd(Nq@'MgL8αw<-c HN&;Pm]|([Xβ.{B}2hNfSMBL:xγ<*π܎Q |F;hb90%Sf󛉼L{Ӡn70#JT ݏDbltϼiEָ5aAj:ǫ&k]s7af;˼FC/D0JH `!B`j>l:HG#XChH5~Xh(D9QlXbxe8ϸƓ|^#h8jLà ?]P1}Da 9mPȅs\ w?Nf(Mru$O2Ňl{jqL U>r@8ցru#A|[ڜ`wzj/Dcݲ>zG@v##?7eD?10D߽@C< }r@®DG4AD=&/Q<wZϾc?-9%D_#O}?xݑ{!f/cfy/Cӗ7}Q}d66 @y0 ހmp ~@ 0 rvh0~~G7> Cw|v ` (u65vyx}FL;vov|hI}P wyт@|@Fjpjw W gzMDHy8X8u؈ 爒8uxvJȉfԗx]VxDcG8@Њ88#ŸȌ،8Hؘh(XH縎8X'8}vx9HI fȐ9{Yg  e֑)&yXF,ْK;29?& Y E:6ۑ<9D;'1YLٔr-qGJTYQ 8Vٕ^XR_YVc)fE@)X\ɖrhp9xIuq~i2P},.JY٘ 39 PpɘhI9y93/먚0 b8YٛԘٌY)r9؜/yHٝH 94IIY3|؞ yHɝٟFR}9:!ɠ:z :qL v&q#z,i;A٢2j+:8*h59ڣv-6Dh@*EvAJʤRgN*WSvV/`Jg\XffBqezleDmn(p*veo/_z|ey/>kڧdB:[Z=zf{`9H1Z3ʩ/e zVZ6!;WAYfڢʫWQ&ʢ9b':?ڬ*p j!7?`!8zZJ@P蚮IծfJC: 1H{ [*PC ۰+#P/!:[/9/\"?`[*+Ҳ13 {)5<8`?A+DAG9@[Ѵ-1T+V ;Y X`+bMd[ !^jkln]DFt w+Dzuc1 ?;eA+zkZ0D4JpD[1" d!cqH`{[}z˼wDKΫ){|JE4˽m{{rH0˾;&RM{gJH<\|fJ l  ZiAh\,[M!#Fo)L,L/ܢ+\Moq4\'zS<>|2CL, BGN,PS#H|3pa\,^a,&[\':`&Z,n|p#r=@l9DmF} 1(yͯNݔM="Y!e%^) L [MVi_lݕj=oq-s-u}wyN~]nE+gMtȇ4ik3m ٍU0ٔC-mמ}٢=Yڝ&ozVڲ Ʊ}F|G(@ڵǍܞ}MiS0M-89mҭ)}=Yߚqߘ>b> « !nގ#%.'~)>$.(4>69n;=^?AC^xH6_ތ[b>F^i.]^lΌegHGv^x{>x(D+.N踸..>鰨鏞NNꪨ风M뱮qΉhk帞뚸.H>~ʾ(QQ^~خNXKhh7>c+^Lވc+o J+_/ /}/?MX݊)o+$.3τ*D79<&EBD/GJ@LPyM/AUyWo?@Z`oa/^G;7h/}0fVprtovc{^V!`G>S_[uo?W{/qVog/Fk?VOO: ;iɟih4 i_OhѿJ>/h ,j?zo3hر -dC%NXE5nG!E$YI)UdҥD4 K9uOA%Zê=*4SQNZU4dP&VaŎ%[Yr]5[qΥ[ I_wĻ+/fqQ3 e̙5ovE&]tX3Cfk'#K8mܹu>1÷jۻ'^pߵg."_u_Nvŏկgo<ϧ_;߿e&? 4@t[A +2O ;Ý2-?&DS I 0QEc"sqFsQDEAO!T?]8rI('JK.tNsLL4dHTM83+7O>DPD:sPBSBUC\QH1tH+ԧF tSNstNC%QSUR34!PMWu֊Z=UDiu~lU^]WXATYf/bYhBu5ZlͶv\>3W\rӅ I0TcՕ7MvOpy%{_+}_ VR`| V`J7օ#\Xbc̀]wac78aKPd{d+َ nyf_Ncs>[-gy~T/ !,GP-XH~ "JHсŋ:cG CydIR~͛6hЅϟ_}AQ7nXT㏧P:BUƆDU#H"Jp)TҦ%{5۷pݲKݻxe.lLgT6ǏHLy2ެ3g ϠCt騨;;u3b˖s۷qͻINxC@KNkNݒ*ïd |̙kϠF%Ț~;vѣWUaUWA&X%vce`Uhf8B8ׄ (b&!WAbhj4Ccsi6jidkͦ$niHWzPA-tݕXRv[&'f?gf?֓{@$_|w~hgVЁ|>a"Vסq9袌Y]V bJʘW+v⋕(Brf׎~ϏYjD)+))j%S6g%utm)]zYA,5[yhmE eyCA'iA+hCP*fjd龃aZb~z">4Aޕjh꫰64dZ]PR t ʖlIK If0ߝN5.Uq a^,Di\!kb T!#B.hS>` d$nEśA>pg' \C'! & Ls݌>K*b朧}_PN:-WY-='nm?OG(ĆB5v7,A(|B~W ҾF4Z?z4H.?ʟ(#̈́41[݊ILmys3 ZPoñK{G^gDZOԿb)}0!\HCO-`nxj@Z!O"H*J8^= q[W$rjCcC5iuT"CPafF;;}KL$nFy!'iz$y8vL*,JVpYxJTޱPe2@s)bnKt[0 IJZЬ~c8cƬ!BR8*]Ir1eCxHRDyvJ: TX{GYA'(~V-,*SK[B|97QeAC!'LPF>f*nA 0hBφ*@ PJԢJ0)¯PꢜJժ*DlK-RCr)TChMZֶܛMvxͫ]׾~;)TaX9j٪YJ*@-1DB?я4ӠtM`GKuN#l־%|qlgK[V6d+RyeHJן#Mr:G0x*ͮvzEH3m"ZMz\`E.{K{᫄_%NM08 [xK;p\"u  b'nA;~lڅ{s:a oFC&A> AC?LB8d=& RHD^rh$ė"e*SBʃ0CF?8ik+πv5?49AF8[pCMM :/w&ZA~X!|@ѐAl@G!h$ngh8d H#Nu4WC|:qCcd?ZvH~x˴3HLl{z4AhvAҡK!w5?FsEWAE šOɲc; ȝv7vل;qj1Yģ gT/ɹAqTCʚ&61)>ukh2.57ATQ\08Z M1\0^7d A}23mvd/~썏'䰳ϼ;"o}:kћoHԻGl/wP;IPO~䅟>ʏS|Ͼg]}?}7&[OϿ[}]x])S X H (xF*0؁ X&H4"Xx,؂$28H8v7@u@|*(H(`jorG'PnzLJ~xxG h؈}舔|/v8w}x(؉6ц~؊X' H'gPȋ¨xh8(yǘH'1XTָ_ gӊ(gԘhc똉btXd-wx֏yV嘏ِ9Iyّ$i_)X*]'9+Ւ) 4\2i5u:ٓ,-ӘT>9΅<BJXF(KՔO)VQ"BNSPy^ GY?@\fJa d)gٖ1kٕn9ieIx9vɖyٗB==w闄9/)|Y(dy"񔊁'\ٙYxB0vOdᚢT)I-=SP)Y-Bʹɚ;9d9Yɚќߩi)y) y4"I99YG[jYy* :J ) ӠI~'BpJJ! Jx_rYny#jY,8C>H1ڗ3+z_I)j)5JbJI9Ĩ Z:r xjS꧞4s:mm/٧ZzJhF9QzfA ڬ :يڭ UzJzʮ,T (jj>׊Z:b}Ȱ +k[k۰#ˍ,9'++-/;1357ˋ9س>@0K:K8H+JشN[PIkT˳V{8Z\۵8:(*Kh"&˶. (2Kر6G˷y跀[F{۸y+c;+j;][[OxBغ 98Kq넹_8;[.x˂ʻ&ؼ 8ԋv˼۽ܫ+{+۾;W~췿{~ ~\w<} |_2S">U=ETw,03D]%3/+9A;=N?n%Ln^NYQ\S^K~刕啹\U^Na]@Jen׉jm]4PH95vDw]|.3i\.狮\N5G^.5 IOi~[c QO1.U~$nNjN<S^nx.NN3jJ#k^Ԯo޾QȞ^NqO>^489EJnoF F /o CO;(sP#%o!),!.o+E#698_0 @B5_r[JNFC?TMK ^?/I?RWR.l(nDl1poNguX/WA!7aoO !,,x@P1(TÇ#JH!Aȑc MiBɓ;R\ɲeK0cAMBɳN#@J蔣HN´ӧMPBիX^ǵׯ`ÊKٳhӪ-۷pBUݻxE:߿P L%iÈ+^ǐmʜLeʑ#sC- !װc˖ݱmI]ҳΗy8B?|<\yQ$H&njνlO>\J_/{_ϸο&`J!4l %m rۃvڀ!fqvh)QWzHx,04^ލNͧ8׎@'aY$]K"Fmt”TViXf9\JHEir1a&b4(t֩x]=獀zvI6裐** eTXv_Vhb9)&bG'9*cjqJŠ`}\*EŤ6kUi CJdvSOs+{zk2%d n=F[ 7+{B«ϊ lz\naD–;@,sþ'Et?Ϻ`-mbw6x[VRMrKao|p.hn'7㐏ݱWnyN޻V褗nzmꬷ.nuVwZh7;G/Wog/'(\T\9n$C!Ās嘉3R.D\hP}+ħCُKx̉Ki Nw #lvQD.@O1$6rz \AC"Pv\($zQ+%.z ݠD("B#rzr_8Ӎ46`6Xd+Xf"I?XTeqF(4OF?KD+&@Z+#EC8fQgcX h&?]3< `] 0(rhB! [N(g~,+px뎮 fHW}~QE(t>h&@ rWVpF gmb, tYPuah8DHi d"+ ĂQ[~ aLs' &<ˈQ\F.ثVK\u*W$˅\셟.u,k7P{Rf/J o &Ob2m #xγWQzT)(: _b.KʎF%s0hPG]5A(pAznV\aMZZ&w^2U}Mbf;[mɖ沟Mj[;VN累n{;Mr%6]mt~MzzηS}7N Ox5;ܔ3dNw27qH [xGN>~\ !vWr8wԧΝ/E8ַ^{.\u|hz3}Kw܃;T؎\fOq /yg*m€OKЫ6Nv۾ܲo=oo r~ovS{wo }OW4BDY)xHIJCNɔS9UYW9P[ف] _ɕY)c e)g9akmdV)hI^iz|ٗlI9 X9geS٘UQyyGr薜9~i9 I~}f7i" |ɚ} Ù|Y)})|)9}ԙyɝ÷izyYʩy{ٛYy7韯)GiǠ頄zyzʡ #*w"z*%ڠ-:w,~74w6z2a>v@h7D*vFz\Ju٤cP٣StRzNZZvYڥR`tb:GWfZth@Ǥlsn:rJstZ2x:sz-ק~r$7qzZqڨp: WZpoo ꨂ,jqwV*GZiکګxZjºڬz:Ԋo֭jo6 oz얮nڮ:n:VmֶJml[vKl ְk6Kk{j۱z g";6V&Kc(,[`.2[\4[u8+X:<ճ>S@ԔD[.yfJ kL۴PjR;yVVKgX5\ c^b_d[uh[jնnWp;5t+Sv{zKN|۷L;T[KkJI[tKIչKX+I[5+}ʺ $Jd+X<ջS4N{֔KMۼ;[K49I۽kJHJ建Kػ{뾞xʽ IX{QH\I \Hl lH G4I\xrx“$L„d„y,I.2HGS5H#Ç8?L,ĆFFHJiE }ILŃdNUL=y*A a'Lid7cvWw[ m|_LmDkloy)i;|i䟀L6FYRJVY%Jd\v[^s)V(lU(ohY7Ng&tw5R7)kV i(`_?JICZy VjoEc\)p*ꨤ木FM)oUTt9(I\*\νTuGꡩF+쵿붹eW)vTJ_YjHE?/2{>U+0VAҟGi#JZ.%](0o ,$lr] ^orRܯH D_U1emWbc D$yj^J֙ДǂK;ᩍA΁N'@aJZ aLXM2Vw 'ǢL4YqdMIrL>ٸ3<+G`IA%hn$6Yk6L%Yuγcx=03M ЈNtF;iG>їMJ,X7iSazҝ2yԨNqJfU$M Z,wkԽ-b [ 4lQ#)nUͶzunkV+h܈.7B?{npuF֍~Y1fCO8=/+Ef G|( 7c%.iL<#OyKr]V&]{6-RqwU|<:)}s}DїPӋ1(ֻ+}`bs}~NEKl;N1xiPp_x, ƓO{'/;{e|?Oz8/u~Qb۞ZIwמi7I;?TلOE.ǿ\OU6~?8?ͻ~?/+e6H~owy ؀ z'għǁ"($X x(-( h釃1ǃ5(GhCoEŇ!脰RH~TXwXxL[|Zb|dX׃hzj׆nyp7tHyvxzx|؇w8xW(wlxvauXVwuL؈8lX 䅩(x>HzȊx(uXu؋8y8WxxȘxHXw˸ިk׍8xhv؎8cZ7vZc0֡b )6$_&zɕ*:\,ڢ0V2:[U6zR8괣<:N>BIDZtHHJwԤNGPi4T*FVz^ZE\ڥV`JEb:KTfDhGlC؄oJ8Yvxѹ|J~Z ɨjԉZE:STDHjD>CZ:t*C0ԪB%4:Bz!:Aګ@:Sz;ghE]zEZUt:EںJԭފDF4Cz*p,۲2<7{;4;;B=?99}CkBEGۯ+kK˴0O MS;MkW8E[5I_/Gc;g;1zjӶQp2r[t[sno뷈(Cykbs۸+*;pR}^˹)㹅 tKZ3/n; Bj29뻦s')ckw뼿u+%¼k0ͫ˽3"D+B6kтݫ᫾ix&2km¿kZ) FR^ X5E6U b$6{P 6|6-lVUFV̱ VvƦ,sf۬ -Zڕ[W@#Btt`=ЀHkYEFfg1m%H!fV23^-P#{^#Nd6B["q#K!05 WT /877 VF"*]F  Cȅ~(1jbcHIPBT E-['t(Z lا?&/GpS6٣WG dy> }ܨEB|( $@!ŔL*wPJ"qJ, )Ft9Z |$xt6Z:H4{1aZؤUL)U4/M.L:)5)%lğ4B~= jy/PE!YJWp6[2$oaFe.u! "b %MLgJӋn hhDcZ5P~Z6UYArî~&Z O,gVՂD\ψSj<K,ԣe$]k BD%keυT1,#*. Ӯ: 9)*NU]—DYSP'MۍGDQ.o UWFF9|Y,A kAFgEkZ f?o\䪊ݼj,zŮɍZY4 BclV3-qmC3&1siKEZ@5H|VZX֗mEnbAȠ*ͰW.rܦ<)D)zY޵pBtt7BH:]xǗCɷBR$#+7}?) S (EdY7!1H' &z9:ۙql"ENV\WLrK.a4ldաEȝm|j21ո!>3(; sꙐr;LR Kk!nU˒T@6g}h eٳ әMbN6f;&NLiCV7wL`މqCl6 mەB罸2"<$qfM67o/߷ NSvrnkx-NC\w;N~#2gLg<.aE{0Ї ^68sq!#'ԧW +ǷQtO`{s7d׾thgN牿Ч~+_s7ugH ag׀Xx؁ "8$X&x(*,؂.0284X6x8:<؃>Cx@8Dxdg'H؄ؤNpoŧ~GP(\xZX z]XA>znW}f5}z6r tpLa{uu:}z8:` (}G腆؇mYXMׁ؉8Xx؊8Xx؋8TDŽ Ntv}AAmx%IluѸ<׆YX;Hjdswf{liH~vƆ|q]{LzpX؎7ݨ)Urz!7po)lqb}s YO)pWP~8u)G7u؜Ԣć%{I"z|&zC>Pt i4id7z؟}YQl=z'gcJ{hJOQi}XEWIozxz|ڧ~:Zzڨ﹦ځnZ瘗ٷ:s}Y(pنr$|iY pR9%ꩰlW)뙫DwsHaijrHZ{ٓo oJs͚]@j:o |:mߚxz蚮꺮ڮ:ZzگRJ[Dj)nasᚬ  x론ٛY; $K([K:)ذt9=(#;q;+!hyxJKشl)@˒LT+V[N+S @*+5ۘ3ۜ:jl۶X ;Iid8v`۷rtHKTk kkؠhL˪u,|۸;WGbL[뉷ș{Jj|U;ɍ )YAk;:vJj[?|IC3~'AڶqzEkZg`q;);軺 [ob{zQ۳KGEZ뗓 :w[9|+ L;,+;lHl¯**:z&|Kll)KJ lyMgʿMB/:zI۵BL5;S,LTĠX|\2\_\[7\9|;^~ fxU |}"a;W J 2"Œ, o\m ݺ~ ɨMˋ,#r< { M~%iꢌw̜\},Unj{Mx jTl0͒MT*w>y<4r|tnL˻6 z Ђk{[$w(EmIVΤt\S{Ŋk[ (a:aZhW=/>˛HmS$>>^~Ӹ8mwӮ#-M;5ٔ״]h1\ӗ1cC>9~ɛCnʯ+-GGY1ۡeص-Σ5,^+5>~Q}3ꃬ|ޔn}A.nJ<H ږk }uԅ22ቯMg{~Ÿ./}Vj Ҳ+K8 y  :. -4_!VO19~\_Ml :u|r\=χm4 +aɂ.mq6?< $؏@cpaC F!#nG!E$YI)UdK1eΤ S̓9+nyQ"Ɵ?1jsĝ ^\SJZThԚYnWaŎ%gӃJ vLڝ9Mk1#ݦSU jݹ [aĉ/fIWR=Ie̙5ogU6iiԩUfڵS.Mmܹuo'^qɕ/gsѥO^uٵowŏ'o|iկgZg{g}<~p@ 4@TpAtA#pB +B 3pC;CCqDK4DSTqE[tE[sq<wrH"4H$TrI&tI(rJ*J,rK.K0sL24L4#(M6M8|3N:NO@tPB 5P*DUtQFuQH#tRJ+t/T974N?5;G5u!,i  H*\Ȱ!A{(!y ̗oL# CyHdhO%H6$~E5`'qYА8̠{\ʷ =QrM74N\# z[/J" gtX:>{FYDWg'5ۏCIMG$Wj̡AoV7!OIw<@јS)UT >=HF>SB!,g>!,n  HC0_>#J,y1b=kw Bp&\i@v Vc'enDQGDs~_AbNr^eMo$'A$K?xB:}*PTт'&J~q!3YB_2 |Uuֶ%/$ 4QP~%3u:s31sS 3dsy4Y/d=: F_VƓnz(,!9k Ja}.9J.NǽS1ͤcU#9EAINf^3$mu@!$g?||QM7c?8(9E!d?JZuuO<)U:gQ?h\;$f3hъET5P5⼣N0PWyyjb]? 莼ˇI1Uk:ꠓN0Ts wqb]PRY!蔫_$14CduI O3ʺ5%b0i0Cjq.X"$v@t=ܣX:<M@l#<!,n  HC=#J,nw ʋ'0yQ(<9K`#b\بY? :HʖjnS#u/GӦџ;!6r5E&L&WFJY`Db!/ 4-Jon]4k4jA(4d4 2h 5 1&41EMݚ=ԧ ܩ:FWU'[#2պm@J\5nrFx7eJeb$ ,K "& yKY"2M/>t,YN\]码QSO=#P# *F _1JM|`%wZeѓH!#=9fre3`HDGpXu?pZXOw ٳPHv O>$Xm!B!,n  HשCPB#J$Hϝs ؏޼g!F;xr˗A2zg\+4x뇦Py0yP&M}.\L4x˱I1Mٯ(Q F`O+1xU-_{1=K~Ff.|~ᢕ3p%ҵQikT!2Eh(L$3_J8CM7D_ԍrv'絕hnM34Q?͠KE_UcMxA< %\P uP~@M$"Vp<|q8\4(JWSR=۵0Sd1Ju,bTfd"&[+O@9#E#OCO><#V?u% G5E5'hNd;=]J<STf!bO!^|_¢O>W\.sI$|ӏ8m^(4NWh9L%K# ^&9BI9m صcpScS:Ԉ;M#uIV#_%Tr n|Eh!DhB ;38a( P"bRN$377_ b," ulwlL?hï=?<䓏4>O͊:U(DJ ks?!4,o  Hˇ`JH =J[Lج(s$uVr?_Ӫ SrS._#/OШsɗy%^D:K)$'QسW(49(W(ߟxHcwFYBI^T|]r(חB$Rw /PܒD8 %'9tnT(4}D>Q6-%/AS:%z‰$(4hs&~6vMcn-@!X%3תݏ=Ss nמ=!,KHDxp 'EDD /2P"1 |CD)ɐWl(cB_Rfi2cʀ! ,KPDxP@(bB%"3!4hDpG4"R&Q(%HEQRҌFA$o:b@!,KNDxP@(bB r2!?h DIb~ bQDD%E"IZQ#ǝ*!,KEDxP@(bBJƢB"c1:Aʇ) R%KS*!,KLDxP@AD!:)(QB &0"Ë&x$Ƃ|SJx SH0!,K0DxP@(bB+RĸQaF 5PdI!,KQDxP@(bBh2!?h8I$¢DbqȘL$ŏd,IcDxztx(Ā!,KWDxP@(bȉEQ E@Cf"Ch)`@)?)@"6>CCDbqD#&щKl"8(RQXE"zQ_b8,vhcɸF3qo<F:pģ;1ܣB9&5I" 3)d}$BDN̤&7Nz (GIRL*WV򕰌,gIZ̥.w^ 0IbL2O28R$|2BĚ\S: YDO!ܴ6׹2?_x;NvS0"*A?'H4mA)5NAIM ^SJFbPK' CE?ҊCۨJ"4$O'љ?+6WSJ8D4AT=MVS|#j)*ZU+NCTDU Cmֱ"^m\J׺"&v+Uv׾*%~ + :>¶f((b+ƒ$^5EYN6ͬGP%ijO]4KZԚ_jXljH-lbBX=Ap;>D0EU+~5oKFЫ`kt2݃TmY]ب /BԚwz W{Kͯ~Gw9MlDzjZ2]}BW)a?SlB0e|F[9fh(b&b 7TKBY2PQ,t!=1e% Ĩ`t]\ VNߓZHYɑi$k!D~r([+M6+2qSYS?;f93!_ ]DWe'EU=L(C飂rrZc4HcN3$Se,'asTX.G_Xsbmh8fH1iecN壆|Fs\*5}{ 񆃸egXpxC^u(؆Rs[*"\N ps9';xuƃʼnƊHfȋR:!Xmcɸk86dԈ芭Kt{t 1\#!~8uRuPg~5DCD{69~T H])!a~bo֏َyX yfv_u q])_>vn,vvXa yP2* . \bC9&8-vC'yMɓ+ٓVYXYi+iajx9$Ad^{j>Ėj1_7t)^w9zgV9An s(A~]Fpqax햃Hx9WJ|AfǕGzFk}8X||Ci|y|w}{aʷYI]كR1~ }!~wkh)(c}5 )FxYA'SIEeaMIA1ȟ-Hr!N(Jh, Xs axVXt1AcrpsXe *!,Jf%M/*0ZraըhCh8xڸOICʍ4aMڌVj\؏EW5舑Uogh qꏀ*בctAtzgIʦJHnWJɔWIZg#?1;Yuu4YiYꪤz3Hcw홫EyRiת)ja)JLhy$Һ_{9׊ۚTzZfH9IڕYH)_5>#1|u:9^˛bz {˚zAۛtA5؝yq ;H:)0˜2+Qu:;r! BK G;4O{!z̘V r!ZFr#zA5&fJ2fa"z4zy lU Kڋ "Gq_L.WA^ DK^zt)Mtx{*{8IHwJj:1ѨKz ٱۻs b [#u:>J(1ϛD ΋˼뼭ٳ:jൾΊn9zԭlqhAeq   IZ `K4A}NIч­I(lD[{.۷w6x[33~֙6;;F|?KL+QS<>[W,p!A0sJ6h W{m̴39;HvxL]{SY(ZZ؆)r|eB4+J/l ,ɍجm |[wSڹJ*D H˗ 5aP4̏ ⎏̥zë x</ьĻ͎j[˫ė;BɔL|L̩Wϲz=A *  L5KmO˿ ҽy})ҙ$ mҾ%4ӴҪӲ$ z> =| ۙ'E]$D ۬M C4lqA 1ZfYKm]}^Ѽ.N,^P^M-ڂDmx06 8) /nk1.35fZȉl;=$*GOc $XA .dC:)T E$JԈ#? (IѠQI&K FhA(4méfΚ?#QȉC)SN)5*ӄRZ%ZKaŎ%T@]nZIv)]"^~9دB" &׮ɢQFn| ˊ,qŚ}~ΥU7<=ڲ1Mz4իa%"$lj/EܷCR^wA{.:x_}{ݼ]O~|0J dhC@A dpB %PB0,2bCD@AĻFE[t3a,kFsqG{G rH"4H$TrI&tI(rJ*J,rK.K0sL24L4TsM6tM8sN:NO@tPB 5PDUtQFuQH#tRJ+RL3tSN;SPCuTRK5TTSUuUV[uUXcuVZkV\suW^{E(, X90 ,MX\HJh=fr֭h*@Y2}HʖCV67 EuLr"^D($,- AA" )$H$[_]tBG8).GLX8! Nl.?pRNa>9e ظe :d1f~ͷ_J'c~7R,l2dܡ'FhgI4PoQvjE]I3lBI3@ëfcGU2qqfE#(|g(N/O$ HKȫq/b; (] cIbP!:Ab23N$BBH )|:6X$;HY ! L ؠFN W^ѹ⇐-wT5cE":qM"N/௘ ]51&N&gF<&$.#5#"/EFS@W.^dVF Hqʕ];|ABvq cj}k[-EF/ְ`A*:ъz ]Җ=ĥ&J'3 ӌd-҄$GLxSV\АdQV_=Yތ!)=#^/?2Fox<8NYbX?:RwA\4cп%QA0zO^ /t^BŇN9e(u1*"(Şf)TdHۗGN<&_VM&ɍozPEsLۈB٬?-+a jI2|X[_"|O %yݤ?}·II|X&Я*ʊYԢ]#Mf{>|mx[w}o|[wo\'x ~p'\ gxpG\x-~q:Yl:q ]9^r{\(_O1Y^7yy]Cyent]Igυt}Q:ХtWS:׷SWL&D'Tp'iN5l/=t{w{ >x]{+S^|=yУ^'M;v%S:}l_~|G7>?}W?~o??/?~_~?G?o_G @c@(@D@4d6s@l@@@  @ @ AC< D8$D@BDCD=TAtFdDC|-p1@ DM4ODEORDP4TDER\Q EXTVXdZ|EYSE[E_E`EaEbtb_Fc\Fd cEffTi|dFgklFf$i@/,;3G%Bǯ)G]Kv\Gu$xds|GyGztzG}Gxy HH~ǂǃGGdHlȅHȇHLȋtȌH$HHHɎHɓ,IKx,c$əɛ|ɝɘIɞJI9LXD"OD i0Bk [ d J# y#'HB/!"ɱ!RȘc >"=RARUtAa3ڙJ7D8uR+RR34<`#{"6Ű O5]ӰS2+Q]T q U40UqR,m&YP*UT GIвISJmSO=,ժԛ9!jQI4+)VA]~8pxpSB%BSdՈ VTxLF"vwu1"[֑yМ u8wBf$вtUה R֨HѧX{6(X(ocp)Ű'5a[xX= *O%ڢW8F˂WcǏUu7~Jb+)t*)TiXԠ&@ e۶=-iB(INp$ۇ!,ODxP@(b#'!cQ@"'$aFQMdʓ%=:@4Tlز 1 ! ,HDxp 'EDD /2P"1 |CD)ɐWl(cB_Rfi2cʀ!,KDxP@(b/ AȉEE!#DD) ɔ+MTɒ˙1[i"E!3,0DxP@(bB+RĸQaF 5PdI!,QDxP@(bBh2!?h8I$¢DbqȘL$ŏd,IcDxztx(Ā!%,WDxP@(bȉEQ E@Cf"Ch)`@:?FMݤP_ %y[x i B@9$FFxeQ@!,  H*\ȰÇ#JHņ2jpǏ CIF%S\ɲˊ'3I͛crɳϟ#uJQB*]eҦPJtիX Vʵ+ӭ^Ê vٳ.ˢ]6ڶpJ|+݇mt_{<8p^ˆ書1Ŏ#,Xʖ3gŬTΞC/-4QҦSDuM֮c-vɀ!-, <*\ȰÇ#JHŋ3jȱǏ CIɓ(QeI \ʜI͛8sɳBv( B( )JR)BNJP(џGz ٳhӪ]QR1aذ}X V &]z+Qۺz'&^GX#G!ӨSF-P %5|QD". p?߈u Q+_W +FKW" Q:kW\ .C!(%2Hz1 |DshT)seJ|~Mn3H%-r늍G/(BZ @ @lL2&"x#rP-li2 gwI+#5ǧt.d2;Izړ&dȧ> |%'ϊTj%CAϲUD'JъZͨF7ю&ӝМGEǣ(M)wPn6R+'3i2tsҗv%JJTtj$;L ECҥBUIZԮz&[RǎĹSg=Tdwl*.SyR1+VV5<+_u6tQ}JxMѫM嬰V5We#-{ٲ kKW =N_)tֺ!kUL+ڲUvf)+Wr+pqͻDTzyԋV_KݮNV},tgZ.9SnH=2'xZo\ӭ~Uz%Ye{ɦ7u7cS"So};Z6թ` zذ}/hMep`WUŋد+ms%ku^ȷŮY;_Wf2p,X~^_cS檐< #G7Lɥf삗po~Y6sF͝[8πɞm<@ЈN E;ѐ "MJ[# .N{"Gm i=B>G=ϝT)GQ"jD^:ަ:u*PpTw*UUDLH]66IebW0fBv[8е~{+7C:8{ :}P/Y:NgG CJA*LK,d+jLZ餭JGdqЇHOѓnNԧNVϺU{eq i]Mvgcowhw={>O|/xeEGXZ@M8JLSTF(XY؅\UWx`G5CVRJR$$Gc2&z|؇~@rf=4; @yp7qbD8𗉘lj׉hxhȊ`,q4dCfp;*CDQr!!L$+W̨(ϸӈ՘؍Xq0'2qׂrk5s0s@3kJ][^ȏ8Vb(  I OHa,gfP (`בZ&t蔑'%Y3Fu"Yt&ْ.0294Y6y8:<ٓ>@B9DYFyHJLٔNPR9TYVyXZ@ifUXǕb9.uI!T\ 1Lf] .Ts6uw:chAoԡcBq#Fw,)|7 !!t0q͓y !?o}U&hUt3ј GRQ a9! N < #aqLYTw"3kI %VB%|0 NsJ !{fIysW';w"`BKA]QvF "`$"H"!y# !H?zbɟ (ZB c"q9]l8'Ȇ'(b-ŃH?3(){*tB2*Ͷ* m!)B`TtyB(P[JV45-Z\)^a3yɢ ezgJ)}Ħ*b՚s 6C !4?KV,uQpp3n6 5x:3:x#h a·ZZ \Aj9-0󪺪ICe Wo_y4t:dE*7A*l31iIuk9uCJq z!n )J7ZŚ3ЪQҪ1֪K#D}4,J@hpW8G4ZϓȚzk/"{ڪtxCc:ʫc$*5) Asr6ZG_4uvEy%qqC!pTʥi+d۰*Bbht IaOzEy{;}+SB yZwEz˷V%3PRR6g"ۨZ IR^{?(vzHCi |#G9'Ghyk=W0꩚aKj-L.ô<t L {aLн!k-˼Ǥke^i)97 SD(ǿKt$9Uy&0O[BPe[N8ᙠ^f\&|(<̓ey9w9L:-?Aǜm;@n9[AHELO|G,JlBZ1_|P#U|dL^,hñ"awyaٿA  a)q: !ԙ^ĉO l\NPȑ,W꽆܄ڛqy]>^0BKF^A GtBJ a89a۪Wf;8&SK:ߦN>׾L~ګ~Gˣ] |:x |Wf۫$n ka~cy6:2kAWqʱ]kC{;Hk_ˍۥ}ʘ@9U:n9ToL2^MҳQow~upW[p ѷt3a˒f$2s'OAި:ug3f2:o;D V_0BБk d˸BKY|/<; ƉLoo=mZ:Y~<,^ω{_D٬~Ko_߸s:%*-OQ?٠?Ĝo "#HP^#瓙zjbzk_k{l6lFWRp;oƳgIKN;cajӘU=)jq$RBq.ibN$<'=)ӊ=WR鐂 {,V >LUXӪBf{&LP@V4TLE9ҟgXzs~s,f XQ5N\Cp$L [Gⵆ@RY[$vYv6f-h5vheQ/namd \~^f-9Ā"`٫0<l{+Z%Wdc _!Zd+%Ayլ>5=f0ZDKEMꑏv9w׼n ۷t#̨;kHCZJl23Ŏ1v؈9sU.udG@%؏1ܘțnAC+ #[5Pcm3C232dCk?4L>GYô6$ ;ë9YB*$ |<0DMC璾@z@LD;:)4D ˺zjC,Zt.Z=CDLDSD[=E*³:#DcILgT? Dq?{?3;i?D#?t43aGnD5k,? XFb;hln˼7[st D9ť8,H5̻a$L+|I͋I$4BɕʞBWұDžl,F@ɧDgEǟ1$H|~ҋDJ,ߊ/D"^$JJ²C'6.J\D#{DH9.MSHjLDFÌʪ*5=T47UZ1Cǻ?u>єLDm FudӜKBn\NQ̢|z@XG=GCFS:M,m^ >;E43e D>P4|LTb$S4%7FNK!%Tk{8 IHO}t}ҥwVEWRuSOϧ{/WJz XjB>ϴ@}&P 25r 4K&TUދUKϫRR~]Oz=}ČXQҤDˑK3\.Et#d}sˬ08ٍM|\ݻ[ A-JT1 Cyݞȟ--y[õ]h ^^-]]U^bOސuT݁FJ]QEQyd85ʲ]EϽP`T(+1{_4jj-܈=˵ܺߘT`jB`fY3Y3PįK %=DM,3jӛiw J1I~1Z1&4@[s1~ ,bVN`E;۔]gU"_rMD ^=D]Y:.2nbٍSIĝcv=c|O?6S%߹m>> P~B7`m^HdIdJdKdLdMdNdOd`Peo`R>f)aT^eeaV~eXeYeZe[e\e]e^e_e`fafb.fc>ed^f)1ef~Qehfqejflfmfnfofpgqgr.g_]d>c!Ot~凳m@u?}gx̸5?|dy^Z=Vgc66tfUU(&Ul_M|; ֻ%f YDJR.wߦ؋#;NaU4~ 7^4[X鞎F%iXg.\.m#課(e=#mj*GԎjkFKվ6bU?tOnퟶ`l2UuSl?5,WNԸk=vEg=f6:5o.C!hMC^K[f}FR~oyh&mOkcsL-_UN2{_ qq/q?qOq_ ;g~bl/fӮqqqqq r!r"/r#?r=7D~rGJ;0\Crjߦ2j.6)v z%17po?q5%W\k۶K&cY@)fjiB2kFW$C\3vֺMoNh+9RuXuYuZu[u\u]u^lNs_d;tboG?ve_vfovgvhvivjvkv24VL\Jowpvr?wEwo/qOww_wuwwxw u]Uvx7w{ozxzx'xGx~7?xGr2LӍ7x'Wyyy_yyՊW */z?zOz_zozzzzzzn\݄-ݮzUz/{_?{)ᬟ{{{{{{w Fږy/|G|ŧ?|Ɵ|ǧ|ȷ|ɯ|Ϳ||ɏb|?|ԏ7W|ڏ}؟}ۯ}}yx{hO~~/~'~W_g PvMv~~/LvaO4v/d~,h „ 2l  FhbĊ7r#Ȑ"G,i$ʔ*WBRaƌ5RtPf1]ӧN4JfΘlh)ԨRRj*֬2)ҠE&V"٭6vES+Xpҭk.޼yw _B߶ L(۞#>LAb ~lg-m4ԪO*pcE {Њ6-4A-kgmyk}8qq]m:گgMj`#wNfy哅ٱW̹zzӹ,Zawbmw *DW\!xq|\ն_p5slaۇ1}h(]s!2x#9ꈚI0Š!`ѦqYf5 Bya2YXaL g%ya9&+QV}Cmߛ2ӓz֥ŭ^mc@נ5W&*hBZҖg.ʆg}5(a0z6:ZUޜ(*|hHeZ+&$]:*,i:;-~j-;;.b[.骻.[{/T/k|0v]x%0w R(1kܫ!IF_C<ԃ=NX"z=Q@DѕKh2`ph<@N42L\4"OT<1ObId#DO8sN0`C\Og>QJcZ> !,i  HܵCB#J$ϛ@v Γq@z P:(AS,@J 6bϥ~iP<%R)(Q#u|[y˘gּs|QNqԠ~01?آAh3hť4%z2z;4dLFs q5\h%:<ТDMMkY׫HP!rQ"3 \!o~ٛil"MhuYӥFdyM5]eJg!7~Ă'wZA)6M:bN4 TO?R#$IF%B51(Տc5Y#HL"3]W1vB3LG 1;hWd@ VQ2H!F5g^ŒHtu;cQ?ވ#:lty3N4F5V?cA׳=1t#=n=L=G!,i  HC=#J,y {^~1d FIN\ɲ`#4*HR\y`Q)ѭD~bH˘3 SMzwVD5].xMg.jMD/d&E 4Fc/xdPUȌ_& /DY"QK_(1?sU(_eVH޼t9gQ.iD~c3W~\.K'ޙDq(J#JhИ!ӍBpwkRPN}g9!p|!Pb%8^4JISS=pOV:5It ~cBN!(k%%Nv zxb"p#(E9j8%:' ^8>sG7<;,"?!,i  HCP>#J,xz hO < Arɓ\cG C`Id%%W>(¤ǒ 2$ R{ 8o\,׭/tү^%h1HnG2+AQ(N"sֈR)=Ϟ94)!h3_~0˞( {M!Žs/] Bc?%Z(W3L"$3j{hh2K)c?g6{=j^N(kS 3M3=(9I4REeUEo ClŢ\NkD(rJѐG&A& Z2o^D.C滇ϧ|9w/Ӂ$WldIDyyf]H\|kQѠyDBh-fM8!SΪ›4g' hmjHDfy\wI\_ H%zHU$$Rhfv54O("a>Q61%/L&=ڶirhܰkqMMF>0'@0?(S!k KZqFdee }:;;;\>n޼tF ! jxoV^xuE.O7oƊ+BuEtƍorss[oGYaa!oߎ~wΝtF !Wdl߾Νۯhw۶m.!aUUU;+~;{qVjϘ?'V@pՈ]vY%&i3 !duT){uxb)5xb]&1 o4S$zHtJaB!Sd0[W#A=.*m Ba7q8X (L!d")y „BԎ 0m8t废Sx~0`B34uj1V T`&vB!3N$Ѓ% *1LAABkO6,K-w  B+5x* &R!B !>g!S10a B  2Vz$6>[yxd|*TjB| h. Bo8-H0!/N ѭNKaBP8U}?AvBV΋ƺxH<כW(kTM+17.ԩǯoWZV)1fˆEX$'/f.kTDQEVkG'dtj=X5/?#Aᘿ' 2oxޥNTAk;fADXy\ ulغSǛPڠuHá0!V8T~[/يo*/[6"-Z:Eq18uNj;Wݲ!~I2)[m9G_AFeaH]5Q-sYʬ;:cJCHܝ>-@18Yӎv \K(z|]HOgqw'g.HFSj`obVÁ1Tf[wƓ;3$e_ 9Iki*5{'Emsk_oƋ̓UM3mnƻ ,Vliydt~:C-iwm8TG^=?d]#~MsѾy V~Ør pK6=~ zd#3ޑ)0rҫ^/AKW?3a~r7| $x|,ϐ#,P ?.qg$a~xd:ԃ.a}O)z-=hEH.S5iKPLdL縜Q)9IH \*AT?B>f& Aĕ`4Y,#LyS7kEAn"}|4H<5Ba2EZX(Kɂ\~̉”p$G#5*bpo QR߉q ch oZd-, /\`ϔ_ k]ڽ%J ͎x>Ą%0[l(Į5㚁j ]S$>$0 Ve=(uT  jpkq95siM <ܒbT Fܿ:7OL?rÑذ-Y{uƪ_;Fp0H.XÄW͏qˋj32dxob;"NDsV 7%b??Y2jiƻ,6;,Q࡛yO /%9}F~j}CkEEJݳUDX6.V;%HFJ!2&Z~6`ϖ۰eC. 12&fgvz%UZQRl)f:}|.g }` YwcUW;'1u,= ,RX:O7߈9%0! zi1=$P,el^ {uw2"fHK@]Z&d,b3aR؅7ofA\?OGX'錾jGi;!3!* 2 iTq* +E{պZp$\.7g[ %Ph!U2w>ݓaռhd'0?!e>PuJ-EVbd-r"DC,d<էZ~&V 0D$49N]pqfh"p,Kcyzb\@Z3b:760q֖L9;* Ba2U%xD\d^z^PtpZ0}g-{ y^F7ߦ Y]?W~ZQS,6Ä1g;SFh=|'& Χnœ`|e]}*{f-6v+[' ݌+ąbS7ᡛB"ka-YOp|nfݩ>U)|e>>w{{YgKz2қ}@< <3EH%غ1g6@<<^,&1nX&ax-;B(LTXߚϷϏ%Iyq8JgL0Z> ~=&Sq2ܔ MrlРA -=nVorݚ9 m֣+Y>S\O_&BaB%Ejt]N-;4hGFwܹYf3ؘ / Z6}}y<„/.<qၸyw[6tW+:({uhաoM&sr„ҕ>Vcm/R   ;BE}/& mS[M ZVV62h`vKDZP8WNNo w5 `hݦmv .+3NJc*݁VFc[Hv"ŭFsF͚p #?39W'@9?ELӗdLddd`Μ9#?۵k]J4?!ǫڠ3vth6F_rV> ˓h)LQQQ1qqqFҥKo"qy*#b_ cڱTҲ>p{9n& .:h0q0ٳg\ HHHo{od2r\,*ΥirƗU:kZ'z1{C#s4MN4\Gk׭Dȑ#Z%cjOt,|,Mds,q%e7d6'%L3lR[ϗ=3DWWU?V -7ۊUG/1P}g嫘jй>DB~lfUbr4zF;iWϏqFJ>.ARȱ:G`r60W~f 3B[+Wi0q7OZjűcX}/MoES[~|bhphF O]JES[sO,d|yذ,vgӫ bdelYYʦ_|sUՆ+s³K%7Ywcu]m\L5>=ujQX.ǂBDp8^_L&COOs["}KWhehAg|"ܽr>,c,#58xdi-bQX݆]G/1VckE*B@%jԃ&(k|F`L$*Vvcej١4AA#&سgL&l04$7n/`K_1'e'ʜrMk2p}:lj7>/+_Ubi ÑP xpq#_/K}o/C7ͥڞai1.3ي5hh-7q̮k[|ף0Yz5:;;QTT4@d(((իWbCO~;q~*EqCU<.3["۲O\z f (z-a yy_b3xPm0Hh)jvF7VA5i+SR|u]3gf$w.\.} W t~7*_XYd ,H? A(ABhdAoS=A4qNхN-YKD:uu Memb<| j,LGAn"#ǖK%#ן<#R#Y R<hN?hii 0D% X17کTx#o{;KeCȿwaH-c;E%^iעX=vbeRG_?O۶m6^\("//Z݂Do@Y ,.*uzR ~>XGz*Z]rF&x+U/s,ǜ^#VYHK%xt|ܿ:ݣÂ8r2Y>jrv@!)2ѵü>L%=='(HKddM;^εB3h;"%=5B,u[ :/}qiA6-J`5R[Pig(r~ܼ >m.8SYT6]`KJa=L@,#,, b@,HZ-^i;PצƫS hj[dƇۙݔln\(<5u3y$*dh eUk2E\r¡3,P䆹^q}'˃f1[Z)n& ! tmh8ԠSU!">U.7lAR8VZ{{1zW."ܡsky *XNA;Iw,pp3"4ЏM|6ap !P[[ 6 a8u! oo)2d.{ͼHqAc݀j,KAddrn<.ω@ukߔ$]XYWNJ/nFR~H 2uի?4, 0"P,s%be|\<WdDy b7uROdt0d21}:Lâ:yId9ugib (wγpH~^GR\p32ɂ/M70:b!yؼ.@q wl>ݳ`(ܿ: dĆ"/5KD" 0Pm}hhנSGπjidy[p>whYz> !$BDK"AT?bv{th*.]Zz כGdj /5ODuT=*C'˃48$!„BCTB(L!PB0!B(L!PB0!BaB!PB0!BaB!„B0!BaB!„B !BaB!„B ! B!„B ! B!&B ! B!&B(L! B!&B(L!PB!~ĘFIENDB`isort-6.0.1/mkdocs.yml0000644000000000000000000000005213615410400011576 0ustar00docs_dir: rtd site_name: "isort redirect" isort-6.0.1/uv.lock0000644000000000000000000127270713615410400011122 0ustar00version = 1 revision = 1 requires-python = ">=3.9.0" resolution-markers = [ "python_full_version < '3.13'", "python_full_version >= '3.13'", ] [[package]] name = "annotated-types" version = "0.7.0" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/ee/67/531ea369ba64dcff5ec9c3402f9f51bf748cec26dde048a2f973a4eea7f5/annotated_types-0.7.0.tar.gz", hash = "sha256:aff07c09a53a08bc8cfccb9c85b05f1aa9a2a6f23728d790723543408344ce89", size = 16081 } wheels = [ { url = "https://files.pythonhosted.org/packages/78/b6/6307fbef88d9b5ee7421e68d78a9f162e0da4900bc5f5793f6d3d0e34fb8/annotated_types-0.7.0-py3-none-any.whl", hash = "sha256:1f02e8b43a8fbbc3f3e0d4f0f4bfc8131bcb4eebe8849b8e5c773f3a1c582a53", size = 13643 }, ] [[package]] name = "anyio" version = "4.8.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "exceptiongroup", marker = "python_full_version < '3.11'" }, { name = "idna" }, { name = "sniffio" }, { name = "typing-extensions", marker = "python_full_version < '3.13'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/a3/73/199a98fc2dae33535d6b8e8e6ec01f8c1d76c9adb096c6b7d64823038cde/anyio-4.8.0.tar.gz", hash = "sha256:1d9fe889df5212298c0c0723fa20479d1b94883a2df44bd3897aa91083316f7a", size = 181126 } wheels = [ { url = "https://files.pythonhosted.org/packages/46/eb/e7f063ad1fec6b3178a3cd82d1a3c4de82cccf283fc42746168188e1cdd5/anyio-4.8.0-py3-none-any.whl", hash = "sha256:b5011f270ab5eb0abf13385f851315585cc37ef330dd88e27ec3d34d651fd47a", size = 96041 }, ] [[package]] name = "appnope" version = "0.1.4" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/35/5d/752690df9ef5b76e169e68d6a129fa6d08a7100ca7f754c89495db3c6019/appnope-0.1.4.tar.gz", hash = "sha256:1de3860566df9caf38f01f86f65e0e13e379af54f9e4bee1e66b48f2efffd1ee", size = 4170 } wheels = [ { url = "https://files.pythonhosted.org/packages/81/29/5ecc3a15d5a33e31b26c11426c45c501e439cb865d0bff96315d86443b78/appnope-0.1.4-py2.py3-none-any.whl", hash = "sha256:502575ee11cd7a28c0205f379b525beefebab9d161b7c964670864014ed7213c", size = 4321 }, ] [[package]] name = "arrow" version = "1.3.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "python-dateutil" }, { name = "types-python-dateutil" }, ] sdist = { url = "https://files.pythonhosted.org/packages/2e/00/0f6e8fcdb23ea632c866620cc872729ff43ed91d284c866b515c6342b173/arrow-1.3.0.tar.gz", hash = "sha256:d4540617648cb5f895730f1ad8c82a65f2dad0166f57b75f3ca54759c4d67a85", size = 131960 } wheels = [ { url = "https://files.pythonhosted.org/packages/f8/ed/e97229a566617f2ae958a6b13e7cc0f585470eac730a73e9e82c32a3cdd2/arrow-1.3.0-py3-none-any.whl", hash = "sha256:c728b120ebc00eb84e01882a6f5e7927a53960aa990ce7dd2b10f39005a67f80", size = 66419 }, ] [[package]] name = "asttokens" version = "3.0.0" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/4a/e7/82da0a03e7ba5141f05cce0d302e6eed121ae055e0456ca228bf693984bc/asttokens-3.0.0.tar.gz", hash = "sha256:0dcd8baa8d62b0c1d118b399b2ddba3c4aff271d0d7a9e0d4c1681c79035bbc7", size = 61978 } wheels = [ { url = "https://files.pythonhosted.org/packages/25/8a/c46dcc25341b5bce5472c718902eb3d38600a903b14fa6aeecef3f21a46f/asttokens-3.0.0-py3-none-any.whl", hash = "sha256:e3078351a059199dd5138cb1c706e6430c05eff2ff136af5eb4790f9d28932e2", size = 26918 }, ] [[package]] name = "attrs" version = "24.3.0" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/48/c8/6260f8ccc11f0917360fc0da435c5c9c7504e3db174d5a12a1494887b045/attrs-24.3.0.tar.gz", hash = "sha256:8f5c07333d543103541ba7be0e2ce16eeee8130cb0b3f9238ab904ce1e85baff", size = 805984 } wheels = [ { url = "https://files.pythonhosted.org/packages/89/aa/ab0f7891a01eeb2d2e338ae8fecbe57fcebea1a24dbb64d45801bfab481d/attrs-24.3.0-py3-none-any.whl", hash = "sha256:ac96cd038792094f438ad1f6ff80837353805ac950cd2aa0e0625ef19850c308", size = 63397 }, ] [[package]] name = "backcall" version = "0.2.0" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/a2/40/764a663805d84deee23043e1426a9175567db89c8b3287b5c2ad9f71aa93/backcall-0.2.0.tar.gz", hash = "sha256:5cbdbf27be5e7cfadb448baf0aa95508f91f2bbc6c6437cd9cd06e2a4c215e1e", size = 18041 } wheels = [ { url = "https://files.pythonhosted.org/packages/4c/1c/ff6546b6c12603d8dd1070aa3c3d273ad4c07f5771689a7b69a550e8c951/backcall-0.2.0-py2.py3-none-any.whl", hash = "sha256:fbbce6a29f263178a1f7915c1940bde0ec2b2a967566fe1c65c1dfb7422bd255", size = 11157 }, ] [[package]] name = "backports-tarfile" version = "1.2.0" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/86/72/cd9b395f25e290e633655a100af28cb253e4393396264a98bd5f5951d50f/backports_tarfile-1.2.0.tar.gz", hash = "sha256:d75e02c268746e1b8144c278978b6e98e85de6ad16f8e4b0844a154557eca991", size = 86406 } wheels = [ { url = "https://files.pythonhosted.org/packages/b9/fa/123043af240e49752f1c4bd24da5053b6bd00cad78c2be53c0d1e8b975bc/backports.tarfile-1.2.0-py3-none-any.whl", hash = "sha256:77e284d754527b01fb1e6fa8a1afe577858ebe4e9dad8919e34c862cb399bc34", size = 30181 }, ] [[package]] name = "bandit" version = "1.8.2" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "colorama", marker = "sys_platform == 'win32'" }, { name = "pyyaml" }, { name = "rich" }, { name = "stevedore" }, ] sdist = { url = "https://files.pythonhosted.org/packages/9b/e2/c229cdb4eefc124e5b77ac2557eb0a3cb5b9fc89bc465dd2b8dc1033dbb8/bandit-1.8.2.tar.gz", hash = "sha256:e00ad5a6bc676c0954669fe13818024d66b70e42cf5adb971480cf3b671e835f", size = 4228832 } wheels = [ { url = "https://files.pythonhosted.org/packages/1c/c1/991a7a1404626558cc7db0cc34243e13e5e336eba053bf6979e9fd6006f7/bandit-1.8.2-py3-none-any.whl", hash = "sha256:df6146ad73dd30e8cbda4e29689ddda48364e36ff655dbfc86998401fcf1721f", size = 127049 }, ] [[package]] name = "beautifulsoup4" version = "4.12.3" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "soupsieve" }, ] sdist = { url = "https://files.pythonhosted.org/packages/b3/ca/824b1195773ce6166d388573fc106ce56d4a805bd7427b624e063596ec58/beautifulsoup4-4.12.3.tar.gz", hash = "sha256:74e3d1928edc070d21748185c46e3fb33490f22f52a3addee9aee0f4f7781051", size = 581181 } wheels = [ { url = "https://files.pythonhosted.org/packages/b1/fe/e8c672695b37eecc5cbf43e1d0638d88d66ba3a44c4d321c796f4e59167f/beautifulsoup4-4.12.3-py3-none-any.whl", hash = "sha256:b80878c9f40111313e55da8ba20bdba06d8fa3969fc68304167741bbf9e082ed", size = 147925 }, ] [[package]] name = "binaryornot" version = "0.4.4" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "chardet" }, ] sdist = { url = "https://files.pythonhosted.org/packages/a7/fe/7ebfec74d49f97fc55cd38240c7a7d08134002b1e14be8c3897c0dd5e49b/binaryornot-0.4.4.tar.gz", hash = "sha256:359501dfc9d40632edc9fac890e19542db1a287bbcfa58175b66658392018061", size = 371054 } wheels = [ { url = "https://files.pythonhosted.org/packages/24/7e/f7b6f453e6481d1e233540262ccbfcf89adcd43606f44a028d7f5fae5eb2/binaryornot-0.4.4-py2.py3-none-any.whl", hash = "sha256:b8b71173c917bddcd2c16070412e369c3ed7f0528926f70cac18a6c97fd563e4", size = 9006 }, ] [[package]] name = "black" version = "24.10.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "click" }, { name = "mypy-extensions" }, { name = "packaging" }, { name = "pathspec" }, { name = "platformdirs" }, { name = "tomli", marker = "python_full_version < '3.11'" }, { name = "typing-extensions", marker = "python_full_version < '3.11'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/d8/0d/cc2fb42b8c50d80143221515dd7e4766995bd07c56c9a3ed30baf080b6dc/black-24.10.0.tar.gz", hash = "sha256:846ea64c97afe3bc677b761787993be4991810ecc7a4a937816dd6bddedc4875", size = 645813 } wheels = [ { url = "https://files.pythonhosted.org/packages/a3/f3/465c0eb5cddf7dbbfe1fecd9b875d1dcf51b88923cd2c1d7e9ab95c6336b/black-24.10.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:e6668650ea4b685440857138e5fe40cde4d652633b1bdffc62933d0db4ed9812", size = 1623211 }, { url = "https://files.pythonhosted.org/packages/df/57/b6d2da7d200773fdfcc224ffb87052cf283cec4d7102fab450b4a05996d8/black-24.10.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:1c536fcf674217e87b8cc3657b81809d3c085d7bf3ef262ead700da345bfa6ea", size = 1457139 }, { url = "https://files.pythonhosted.org/packages/6e/c5/9023b7673904a5188f9be81f5e129fff69f51f5515655fbd1d5a4e80a47b/black-24.10.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:649fff99a20bd06c6f727d2a27f401331dc0cc861fb69cde910fe95b01b5928f", size = 1753774 }, { url = "https://files.pythonhosted.org/packages/e1/32/df7f18bd0e724e0d9748829765455d6643ec847b3f87e77456fc99d0edab/black-24.10.0-cp310-cp310-win_amd64.whl", hash = "sha256:fe4d6476887de70546212c99ac9bd803d90b42fc4767f058a0baa895013fbb3e", size = 1414209 }, { url = "https://files.pythonhosted.org/packages/c2/cc/7496bb63a9b06a954d3d0ac9fe7a73f3bf1cd92d7a58877c27f4ad1e9d41/black-24.10.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:5a2221696a8224e335c28816a9d331a6c2ae15a2ee34ec857dcf3e45dbfa99ad", size = 1607468 }, { url = "https://files.pythonhosted.org/packages/2b/e3/69a738fb5ba18b5422f50b4f143544c664d7da40f09c13969b2fd52900e0/black-24.10.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:f9da3333530dbcecc1be13e69c250ed8dfa67f43c4005fb537bb426e19200d50", size = 1437270 }, { url = "https://files.pythonhosted.org/packages/c9/9b/2db8045b45844665c720dcfe292fdaf2e49825810c0103e1191515fc101a/black-24.10.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4007b1393d902b48b36958a216c20c4482f601569d19ed1df294a496eb366392", size = 1737061 }, { url = "https://files.pythonhosted.org/packages/a3/95/17d4a09a5be5f8c65aa4a361444d95edc45def0de887810f508d3f65db7a/black-24.10.0-cp311-cp311-win_amd64.whl", hash = "sha256:394d4ddc64782e51153eadcaaca95144ac4c35e27ef9b0a42e121ae7e57a9175", size = 1423293 }, { url = "https://files.pythonhosted.org/packages/90/04/bf74c71f592bcd761610bbf67e23e6a3cff824780761f536512437f1e655/black-24.10.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:b5e39e0fae001df40f95bd8cc36b9165c5e2ea88900167bddf258bacef9bbdc3", size = 1644256 }, { url = "https://files.pythonhosted.org/packages/4c/ea/a77bab4cf1887f4b2e0bce5516ea0b3ff7d04ba96af21d65024629afedb6/black-24.10.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:d37d422772111794b26757c5b55a3eade028aa3fde43121ab7b673d050949d65", size = 1448534 }, { url = "https://files.pythonhosted.org/packages/4e/3e/443ef8bc1fbda78e61f79157f303893f3fddf19ca3c8989b163eb3469a12/black-24.10.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:14b3502784f09ce2443830e3133dacf2c0110d45191ed470ecb04d0f5f6fcb0f", size = 1761892 }, { url = "https://files.pythonhosted.org/packages/52/93/eac95ff229049a6901bc84fec6908a5124b8a0b7c26ea766b3b8a5debd22/black-24.10.0-cp312-cp312-win_amd64.whl", hash = "sha256:30d2c30dc5139211dda799758559d1b049f7f14c580c409d6ad925b74a4208a8", size = 1434796 }, { url = "https://files.pythonhosted.org/packages/d0/a0/a993f58d4ecfba035e61fca4e9f64a2ecae838fc9f33ab798c62173ed75c/black-24.10.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:1cbacacb19e922a1d75ef2b6ccaefcd6e93a2c05ede32f06a21386a04cedb981", size = 1643986 }, { url = "https://files.pythonhosted.org/packages/37/d5/602d0ef5dfcace3fb4f79c436762f130abd9ee8d950fa2abdbf8bbc555e0/black-24.10.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:1f93102e0c5bb3907451063e08b9876dbeac810e7da5a8bfb7aeb5a9ef89066b", size = 1448085 }, { url = "https://files.pythonhosted.org/packages/47/6d/a3a239e938960df1a662b93d6230d4f3e9b4a22982d060fc38c42f45a56b/black-24.10.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ddacb691cdcdf77b96f549cf9591701d8db36b2f19519373d60d31746068dbf2", size = 1760928 }, { url = "https://files.pythonhosted.org/packages/dd/cf/af018e13b0eddfb434df4d9cd1b2b7892bab119f7a20123e93f6910982e8/black-24.10.0-cp313-cp313-win_amd64.whl", hash = "sha256:680359d932801c76d2e9c9068d05c6b107f2584b2a5b88831c83962eb9984c1b", size = 1436875 }, { url = "https://files.pythonhosted.org/packages/fe/02/f408c804e0ee78c367dcea0a01aedde4f1712af93b8b6e60df981e0228c7/black-24.10.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:17374989640fbca88b6a448129cd1745c5eb8d9547b464f281b251dd00155ccd", size = 1622516 }, { url = "https://files.pythonhosted.org/packages/f8/b9/9b706ed2f55bfb28b436225a9c57da35990c9005b90b8c91f03924454ad7/black-24.10.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:63f626344343083322233f175aaf372d326de8436f5928c042639a4afbbf1d3f", size = 1456181 }, { url = "https://files.pythonhosted.org/packages/0a/1c/314d7f17434a5375682ad097f6f4cc0e3f414f3c95a9b1bb4df14a0f11f9/black-24.10.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ccfa1d0cb6200857f1923b602f978386a3a2758a65b52e0950299ea014be6800", size = 1752801 }, { url = "https://files.pythonhosted.org/packages/39/a7/20e5cd9237d28ad0b31438de5d9f01c8b99814576f4c0cda1edd62caf4b0/black-24.10.0-cp39-cp39-win_amd64.whl", hash = "sha256:2cd9c95431d94adc56600710f8813ee27eea544dd118d45896bb734e9d7a0dc7", size = 1413626 }, { url = "https://files.pythonhosted.org/packages/8d/a7/4b27c50537ebca8bec139b872861f9d2bf501c5ec51fcf897cb924d9e264/black-24.10.0-py3-none-any.whl", hash = "sha256:3bb2b7a1f7b685f85b11fed1ef10f8a9148bceb49853e47a294a3dd963c1dd7d", size = 206898 }, ] [[package]] name = "bleach" version = "6.2.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "webencodings" }, ] sdist = { url = "https://files.pythonhosted.org/packages/76/9a/0e33f5054c54d349ea62c277191c020c2d6ef1d65ab2cb1993f91ec846d1/bleach-6.2.0.tar.gz", hash = "sha256:123e894118b8a599fd80d3ec1a6d4cc7ce4e5882b1317a7e1ba69b56e95f991f", size = 203083 } wheels = [ { url = "https://files.pythonhosted.org/packages/fc/55/96142937f66150805c25c4d0f31ee4132fd33497753400734f9dfdcbdc66/bleach-6.2.0-py3-none-any.whl", hash = "sha256:117d9c6097a7c3d22fd578fcd8d35ff1e125df6736f554da4e432fdd63f31e5e", size = 163406 }, ] [package.optional-dependencies] css = [ { name = "tinycss2" }, ] [[package]] name = "cerberus" version = "1.3.7" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/08/92/6d861524d97a2c4913816309ca12afe313b32c8efc3ec641de98b890834b/cerberus-1.3.7.tar.gz", hash = "sha256:ecf249665400a0b7a9d5e4ee1ffc234fd5d003186d3e1904f70bc14038642c13", size = 29651 } wheels = [ { url = "https://files.pythonhosted.org/packages/15/ce/e3abf3fd04da28978eefb06ea906549f20f23f2ec6df8873ede6b62c8a8c/Cerberus-1.3.7-py3-none-any.whl", hash = "sha256:180e7d1fa1a5765cbff7b5c716e52fddddfab859dc8f625b0d563ace4b7a7ab3", size = 30508 }, ] [[package]] name = "certifi" version = "2024.12.14" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/0f/bd/1d41ee578ce09523c81a15426705dd20969f5abf006d1afe8aeff0dd776a/certifi-2024.12.14.tar.gz", hash = "sha256:b650d30f370c2b724812bee08008be0c4163b163ddaec3f2546c1caf65f191db", size = 166010 } wheels = [ { url = "https://files.pythonhosted.org/packages/a5/32/8f6669fc4798494966bf446c8c4a162e0b5d893dff088afddf76414f70e1/certifi-2024.12.14-py3-none-any.whl", hash = "sha256:1275f7a45be9464efc1173084eaa30f866fe2e47d389406136d332ed4967ec56", size = 164927 }, ] [[package]] name = "cffi" version = "1.17.1" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "pycparser" }, ] sdist = { url = "https://files.pythonhosted.org/packages/fc/97/c783634659c2920c3fc70419e3af40972dbaf758daa229a7d6ea6135c90d/cffi-1.17.1.tar.gz", hash = "sha256:1c39c6016c32bc48dd54561950ebd6836e1670f2ae46128f67cf49e789c52824", size = 516621 } wheels = [ { url = "https://files.pythonhosted.org/packages/90/07/f44ca684db4e4f08a3fdc6eeb9a0d15dc6883efc7b8c90357fdbf74e186c/cffi-1.17.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:df8b1c11f177bc2313ec4b2d46baec87a5f3e71fc8b45dab2ee7cae86d9aba14", size = 182191 }, { url = "https://files.pythonhosted.org/packages/08/fd/cc2fedbd887223f9f5d170c96e57cbf655df9831a6546c1727ae13fa977a/cffi-1.17.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:8f2cdc858323644ab277e9bb925ad72ae0e67f69e804f4898c070998d50b1a67", size = 178592 }, { url = "https://files.pythonhosted.org/packages/de/cc/4635c320081c78d6ffc2cab0a76025b691a91204f4aa317d568ff9280a2d/cffi-1.17.1-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:edae79245293e15384b51f88b00613ba9f7198016a5948b5dddf4917d4d26382", size = 426024 }, { url = "https://files.pythonhosted.org/packages/b6/7b/3b2b250f3aab91abe5f8a51ada1b717935fdaec53f790ad4100fe2ec64d1/cffi-1.17.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:45398b671ac6d70e67da8e4224a065cec6a93541bb7aebe1b198a61b58c7b702", size = 448188 }, { url = "https://files.pythonhosted.org/packages/d3/48/1b9283ebbf0ec065148d8de05d647a986c5f22586b18120020452fff8f5d/cffi-1.17.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ad9413ccdeda48c5afdae7e4fa2192157e991ff761e7ab8fdd8926f40b160cc3", size = 455571 }, { url = "https://files.pythonhosted.org/packages/40/87/3b8452525437b40f39ca7ff70276679772ee7e8b394934ff60e63b7b090c/cffi-1.17.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5da5719280082ac6bd9aa7becb3938dc9f9cbd57fac7d2871717b1feb0902ab6", size = 436687 }, { url = "https://files.pythonhosted.org/packages/8d/fb/4da72871d177d63649ac449aec2e8a29efe0274035880c7af59101ca2232/cffi-1.17.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2bb1a08b8008b281856e5971307cc386a8e9c5b625ac297e853d36da6efe9c17", size = 446211 }, { url = "https://files.pythonhosted.org/packages/ab/a0/62f00bcb411332106c02b663b26f3545a9ef136f80d5df746c05878f8c4b/cffi-1.17.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:045d61c734659cc045141be4bae381a41d89b741f795af1dd018bfb532fd0df8", size = 461325 }, { url = "https://files.pythonhosted.org/packages/36/83/76127035ed2e7e27b0787604d99da630ac3123bfb02d8e80c633f218a11d/cffi-1.17.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:6883e737d7d9e4899a8a695e00ec36bd4e5e4f18fabe0aca0efe0a4b44cdb13e", size = 438784 }, { url = "https://files.pythonhosted.org/packages/21/81/a6cd025db2f08ac88b901b745c163d884641909641f9b826e8cb87645942/cffi-1.17.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:6b8b4a92e1c65048ff98cfe1f735ef8f1ceb72e3d5f0c25fdb12087a23da22be", size = 461564 }, { url = "https://files.pythonhosted.org/packages/f8/fe/4d41c2f200c4a457933dbd98d3cf4e911870877bd94d9656cc0fcb390681/cffi-1.17.1-cp310-cp310-win32.whl", hash = "sha256:c9c3d058ebabb74db66e431095118094d06abf53284d9c81f27300d0e0d8bc7c", size = 171804 }, { url = "https://files.pythonhosted.org/packages/d1/b6/0b0f5ab93b0df4acc49cae758c81fe4e5ef26c3ae2e10cc69249dfd8b3ab/cffi-1.17.1-cp310-cp310-win_amd64.whl", hash = "sha256:0f048dcf80db46f0098ccac01132761580d28e28bc0f78ae0d58048063317e15", size = 181299 }, { url = "https://files.pythonhosted.org/packages/6b/f4/927e3a8899e52a27fa57a48607ff7dc91a9ebe97399b357b85a0c7892e00/cffi-1.17.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:a45e3c6913c5b87b3ff120dcdc03f6131fa0065027d0ed7ee6190736a74cd401", size = 182264 }, { url = "https://files.pythonhosted.org/packages/6c/f5/6c3a8efe5f503175aaddcbea6ad0d2c96dad6f5abb205750d1b3df44ef29/cffi-1.17.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:30c5e0cb5ae493c04c8b42916e52ca38079f1b235c2f8ae5f4527b963c401caf", size = 178651 }, { url = "https://files.pythonhosted.org/packages/94/dd/a3f0118e688d1b1a57553da23b16bdade96d2f9bcda4d32e7d2838047ff7/cffi-1.17.1-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f75c7ab1f9e4aca5414ed4d8e5c0e303a34f4421f8a0d47a4d019ceff0ab6af4", size = 445259 }, { url = "https://files.pythonhosted.org/packages/2e/ea/70ce63780f096e16ce8588efe039d3c4f91deb1dc01e9c73a287939c79a6/cffi-1.17.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a1ed2dd2972641495a3ec98445e09766f077aee98a1c896dcb4ad0d303628e41", size = 469200 }, { url = "https://files.pythonhosted.org/packages/1c/a0/a4fa9f4f781bda074c3ddd57a572b060fa0df7655d2a4247bbe277200146/cffi-1.17.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:46bf43160c1a35f7ec506d254e5c890f3c03648a4dbac12d624e4490a7046cd1", size = 477235 }, { url = "https://files.pythonhosted.org/packages/62/12/ce8710b5b8affbcdd5c6e367217c242524ad17a02fe5beec3ee339f69f85/cffi-1.17.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a24ed04c8ffd54b0729c07cee15a81d964e6fee0e3d4d342a27b020d22959dc6", size = 459721 }, { url = "https://files.pythonhosted.org/packages/ff/6b/d45873c5e0242196f042d555526f92aa9e0c32355a1be1ff8c27f077fd37/cffi-1.17.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:610faea79c43e44c71e1ec53a554553fa22321b65fae24889706c0a84d4ad86d", size = 467242 }, { url = "https://files.pythonhosted.org/packages/1a/52/d9a0e523a572fbccf2955f5abe883cfa8bcc570d7faeee06336fbd50c9fc/cffi-1.17.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:a9b15d491f3ad5d692e11f6b71f7857e7835eb677955c00cc0aefcd0669adaf6", size = 477999 }, { url = "https://files.pythonhosted.org/packages/44/74/f2a2460684a1a2d00ca799ad880d54652841a780c4c97b87754f660c7603/cffi-1.17.1-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:de2ea4b5833625383e464549fec1bc395c1bdeeb5f25c4a3a82b5a8c756ec22f", size = 454242 }, { url = "https://files.pythonhosted.org/packages/f8/4a/34599cac7dfcd888ff54e801afe06a19c17787dfd94495ab0c8d35fe99fb/cffi-1.17.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:fc48c783f9c87e60831201f2cce7f3b2e4846bf4d8728eabe54d60700b318a0b", size = 478604 }, { url = "https://files.pythonhosted.org/packages/34/33/e1b8a1ba29025adbdcda5fb3a36f94c03d771c1b7b12f726ff7fef2ebe36/cffi-1.17.1-cp311-cp311-win32.whl", hash = "sha256:85a950a4ac9c359340d5963966e3e0a94a676bd6245a4b55bc43949eee26a655", size = 171727 }, { url = "https://files.pythonhosted.org/packages/3d/97/50228be003bb2802627d28ec0627837ac0bf35c90cf769812056f235b2d1/cffi-1.17.1-cp311-cp311-win_amd64.whl", hash = "sha256:caaf0640ef5f5517f49bc275eca1406b0ffa6aa184892812030f04c2abf589a0", size = 181400 }, { url = "https://files.pythonhosted.org/packages/5a/84/e94227139ee5fb4d600a7a4927f322e1d4aea6fdc50bd3fca8493caba23f/cffi-1.17.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:805b4371bf7197c329fcb3ead37e710d1bca9da5d583f5073b799d5c5bd1eee4", size = 183178 }, { url = "https://files.pythonhosted.org/packages/da/ee/fb72c2b48656111c4ef27f0f91da355e130a923473bf5ee75c5643d00cca/cffi-1.17.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:733e99bc2df47476e3848417c5a4540522f234dfd4ef3ab7fafdf555b082ec0c", size = 178840 }, { url = "https://files.pythonhosted.org/packages/cc/b6/db007700f67d151abadf508cbfd6a1884f57eab90b1bb985c4c8c02b0f28/cffi-1.17.1-cp312-cp312-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1257bdabf294dceb59f5e70c64a3e2f462c30c7ad68092d01bbbfb1c16b1ba36", size = 454803 }, { url = "https://files.pythonhosted.org/packages/1a/df/f8d151540d8c200eb1c6fba8cd0dfd40904f1b0682ea705c36e6c2e97ab3/cffi-1.17.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:da95af8214998d77a98cc14e3a3bd00aa191526343078b530ceb0bd710fb48a5", size = 478850 }, { url = "https://files.pythonhosted.org/packages/28/c0/b31116332a547fd2677ae5b78a2ef662dfc8023d67f41b2a83f7c2aa78b1/cffi-1.17.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d63afe322132c194cf832bfec0dc69a99fb9bb6bbd550f161a49e9e855cc78ff", size = 485729 }, { url = "https://files.pythonhosted.org/packages/91/2b/9a1ddfa5c7f13cab007a2c9cc295b70fbbda7cb10a286aa6810338e60ea1/cffi-1.17.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f79fc4fc25f1c8698ff97788206bb3c2598949bfe0fef03d299eb1b5356ada99", size = 471256 }, { url = "https://files.pythonhosted.org/packages/b2/d5/da47df7004cb17e4955df6a43d14b3b4ae77737dff8bf7f8f333196717bf/cffi-1.17.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b62ce867176a75d03a665bad002af8e6d54644fad99a3c70905c543130e39d93", size = 479424 }, { url = "https://files.pythonhosted.org/packages/0b/ac/2a28bcf513e93a219c8a4e8e125534f4f6db03e3179ba1c45e949b76212c/cffi-1.17.1-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:386c8bf53c502fff58903061338ce4f4950cbdcb23e2902d86c0f722b786bbe3", size = 484568 }, { url = "https://files.pythonhosted.org/packages/d4/38/ca8a4f639065f14ae0f1d9751e70447a261f1a30fa7547a828ae08142465/cffi-1.17.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:4ceb10419a9adf4460ea14cfd6bc43d08701f0835e979bf821052f1805850fe8", size = 488736 }, { url = "https://files.pythonhosted.org/packages/86/c5/28b2d6f799ec0bdecf44dced2ec5ed43e0eb63097b0f58c293583b406582/cffi-1.17.1-cp312-cp312-win32.whl", hash = "sha256:a08d7e755f8ed21095a310a693525137cfe756ce62d066e53f502a83dc550f65", size = 172448 }, { url = "https://files.pythonhosted.org/packages/50/b9/db34c4755a7bd1cb2d1603ac3863f22bcecbd1ba29e5ee841a4bc510b294/cffi-1.17.1-cp312-cp312-win_amd64.whl", hash = "sha256:51392eae71afec0d0c8fb1a53b204dbb3bcabcb3c9b807eedf3e1e6ccf2de903", size = 181976 }, { url = "https://files.pythonhosted.org/packages/8d/f8/dd6c246b148639254dad4d6803eb6a54e8c85c6e11ec9df2cffa87571dbe/cffi-1.17.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:f3a2b4222ce6b60e2e8b337bb9596923045681d71e5a082783484d845390938e", size = 182989 }, { url = "https://files.pythonhosted.org/packages/8b/f1/672d303ddf17c24fc83afd712316fda78dc6fce1cd53011b839483e1ecc8/cffi-1.17.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:0984a4925a435b1da406122d4d7968dd861c1385afe3b45ba82b750f229811e2", size = 178802 }, { url = "https://files.pythonhosted.org/packages/0e/2d/eab2e858a91fdff70533cab61dcff4a1f55ec60425832ddfdc9cd36bc8af/cffi-1.17.1-cp313-cp313-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d01b12eeeb4427d3110de311e1774046ad344f5b1a7403101878976ecd7a10f3", size = 454792 }, { url = "https://files.pythonhosted.org/packages/75/b2/fbaec7c4455c604e29388d55599b99ebcc250a60050610fadde58932b7ee/cffi-1.17.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:706510fe141c86a69c8ddc029c7910003a17353970cff3b904ff0686a5927683", size = 478893 }, { url = "https://files.pythonhosted.org/packages/4f/b7/6e4a2162178bf1935c336d4da8a9352cccab4d3a5d7914065490f08c0690/cffi-1.17.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:de55b766c7aa2e2a3092c51e0483d700341182f08e67c63630d5b6f200bb28e5", size = 485810 }, { url = "https://files.pythonhosted.org/packages/c7/8a/1d0e4a9c26e54746dc08c2c6c037889124d4f59dffd853a659fa545f1b40/cffi-1.17.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c59d6e989d07460165cc5ad3c61f9fd8f1b4796eacbd81cee78957842b834af4", size = 471200 }, { url = "https://files.pythonhosted.org/packages/26/9f/1aab65a6c0db35f43c4d1b4f580e8df53914310afc10ae0397d29d697af4/cffi-1.17.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dd398dbc6773384a17fe0d3e7eeb8d1a21c2200473ee6806bb5e6a8e62bb73dd", size = 479447 }, { url = "https://files.pythonhosted.org/packages/5f/e4/fb8b3dd8dc0e98edf1135ff067ae070bb32ef9d509d6cb0f538cd6f7483f/cffi-1.17.1-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:3edc8d958eb099c634dace3c7e16560ae474aa3803a5df240542b305d14e14ed", size = 484358 }, { url = "https://files.pythonhosted.org/packages/f1/47/d7145bf2dc04684935d57d67dff9d6d795b2ba2796806bb109864be3a151/cffi-1.17.1-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:72e72408cad3d5419375fc87d289076ee319835bdfa2caad331e377589aebba9", size = 488469 }, { url = "https://files.pythonhosted.org/packages/bf/ee/f94057fa6426481d663b88637a9a10e859e492c73d0384514a17d78ee205/cffi-1.17.1-cp313-cp313-win32.whl", hash = "sha256:e03eab0a8677fa80d646b5ddece1cbeaf556c313dcfac435ba11f107ba117b5d", size = 172475 }, { url = "https://files.pythonhosted.org/packages/7c/fc/6a8cb64e5f0324877d503c854da15d76c1e50eb722e320b15345c4d0c6de/cffi-1.17.1-cp313-cp313-win_amd64.whl", hash = "sha256:f6a16c31041f09ead72d69f583767292f750d24913dadacf5756b966aacb3f1a", size = 182009 }, { url = "https://files.pythonhosted.org/packages/b9/ea/8bb50596b8ffbc49ddd7a1ad305035daa770202a6b782fc164647c2673ad/cffi-1.17.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:b2ab587605f4ba0bf81dc0cb08a41bd1c0a5906bd59243d56bad7668a6fc6c16", size = 182220 }, { url = "https://files.pythonhosted.org/packages/ae/11/e77c8cd24f58285a82c23af484cf5b124a376b32644e445960d1a4654c3a/cffi-1.17.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:28b16024becceed8c6dfbc75629e27788d8a3f9030691a1dbf9821a128b22c36", size = 178605 }, { url = "https://files.pythonhosted.org/packages/ed/65/25a8dc32c53bf5b7b6c2686b42ae2ad58743f7ff644844af7cdb29b49361/cffi-1.17.1-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1d599671f396c4723d016dbddb72fe8e0397082b0a77a4fab8028923bec050e8", size = 424910 }, { url = "https://files.pythonhosted.org/packages/42/7a/9d086fab7c66bd7c4d0f27c57a1b6b068ced810afc498cc8c49e0088661c/cffi-1.17.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ca74b8dbe6e8e8263c0ffd60277de77dcee6c837a3d0881d8c1ead7268c9e576", size = 447200 }, { url = "https://files.pythonhosted.org/packages/da/63/1785ced118ce92a993b0ec9e0d0ac8dc3e5dbfbcaa81135be56c69cabbb6/cffi-1.17.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f7f5baafcc48261359e14bcd6d9bff6d4b28d9103847c9e136694cb0501aef87", size = 454565 }, { url = "https://files.pythonhosted.org/packages/74/06/90b8a44abf3556599cdec107f7290277ae8901a58f75e6fe8f970cd72418/cffi-1.17.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:98e3969bcff97cae1b2def8ba499ea3d6f31ddfdb7635374834cf89a1a08ecf0", size = 435635 }, { url = "https://files.pythonhosted.org/packages/bd/62/a1f468e5708a70b1d86ead5bab5520861d9c7eacce4a885ded9faa7729c3/cffi-1.17.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cdf5ce3acdfd1661132f2a9c19cac174758dc2352bfe37d98aa7512c6b7178b3", size = 445218 }, { url = "https://files.pythonhosted.org/packages/5b/95/b34462f3ccb09c2594aa782d90a90b045de4ff1f70148ee79c69d37a0a5a/cffi-1.17.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:9755e4345d1ec879e3849e62222a18c7174d65a6a92d5b346b1863912168b595", size = 460486 }, { url = "https://files.pythonhosted.org/packages/fc/fc/a1e4bebd8d680febd29cf6c8a40067182b64f00c7d105f8f26b5bc54317b/cffi-1.17.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:f1e22e8c4419538cb197e4dd60acc919d7696e5ef98ee4da4e01d3f8cfa4cc5a", size = 437911 }, { url = "https://files.pythonhosted.org/packages/e6/c3/21cab7a6154b6a5ea330ae80de386e7665254835b9e98ecc1340b3a7de9a/cffi-1.17.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:c03e868a0b3bc35839ba98e74211ed2b05d2119be4e8a0f224fba9384f1fe02e", size = 460632 }, { url = "https://files.pythonhosted.org/packages/cb/b5/fd9f8b5a84010ca169ee49f4e4ad6f8c05f4e3545b72ee041dbbcb159882/cffi-1.17.1-cp39-cp39-win32.whl", hash = "sha256:e31ae45bc2e29f6b2abd0de1cc3b9d5205aa847cafaecb8af1476a609a2f6eb7", size = 171820 }, { url = "https://files.pythonhosted.org/packages/8c/52/b08750ce0bce45c143e1b5d7357ee8c55341b52bdef4b0f081af1eb248c2/cffi-1.17.1-cp39-cp39-win_amd64.whl", hash = "sha256:d016c76bdd850f3c626af19b0542c9677ba156e4ee4fccfdd7848803533ef662", size = 181290 }, ] [[package]] name = "cfgv" version = "3.4.0" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/11/74/539e56497d9bd1d484fd863dd69cbbfa653cd2aa27abfe35653494d85e94/cfgv-3.4.0.tar.gz", hash = "sha256:e52591d4c5f5dead8e0f673fb16db7949d2cfb3f7da4582893288f0ded8fe560", size = 7114 } wheels = [ { url = "https://files.pythonhosted.org/packages/c5/55/51844dd50c4fc7a33b653bfaba4c2456f06955289ca770a5dbd5fd267374/cfgv-3.4.0-py2.py3-none-any.whl", hash = "sha256:b7265b1f29fd3316bfcd2b330d63d024f2bfd8bcb8b0272f8e19a504856c48f9", size = 7249 }, ] [[package]] name = "chardet" version = "5.2.0" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/f3/0d/f7b6ab21ec75897ed80c17d79b15951a719226b9fababf1e40ea74d69079/chardet-5.2.0.tar.gz", hash = "sha256:1b3b6ff479a8c414bc3fa2c0852995695c4a026dcd6d0633b2dd092ca39c1cf7", size = 2069618 } wheels = [ { url = "https://files.pythonhosted.org/packages/38/6f/f5fbc992a329ee4e0f288c1fe0e2ad9485ed064cac731ed2fe47dcc38cbf/chardet-5.2.0-py3-none-any.whl", hash = "sha256:e1cf59446890a00105fe7b7912492ea04b6e6f06d4b742b2c788469e34c82970", size = 199385 }, ] [[package]] name = "charset-normalizer" version = "3.4.1" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/16/b0/572805e227f01586461c80e0fd25d65a2115599cc9dad142fee4b747c357/charset_normalizer-3.4.1.tar.gz", hash = "sha256:44251f18cd68a75b56585dd00dae26183e102cd5e0f9f1466e6df5da2ed64ea3", size = 123188 } wheels = [ { url = "https://files.pythonhosted.org/packages/0d/58/5580c1716040bc89206c77d8f74418caf82ce519aae06450393ca73475d1/charset_normalizer-3.4.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:91b36a978b5ae0ee86c394f5a54d6ef44db1de0815eb43de826d41d21e4af3de", size = 198013 }, { url = "https://files.pythonhosted.org/packages/d0/11/00341177ae71c6f5159a08168bcb98c6e6d196d372c94511f9f6c9afe0c6/charset_normalizer-3.4.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7461baadb4dc00fd9e0acbe254e3d7d2112e7f92ced2adc96e54ef6501c5f176", size = 141285 }, { url = "https://files.pythonhosted.org/packages/01/09/11d684ea5819e5a8f5100fb0b38cf8d02b514746607934134d31233e02c8/charset_normalizer-3.4.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e218488cd232553829be0664c2292d3af2eeeb94b32bea483cf79ac6a694e037", size = 151449 }, { url = "https://files.pythonhosted.org/packages/08/06/9f5a12939db324d905dc1f70591ae7d7898d030d7662f0d426e2286f68c9/charset_normalizer-3.4.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:80ed5e856eb7f30115aaf94e4a08114ccc8813e6ed1b5efa74f9f82e8509858f", size = 143892 }, { url = "https://files.pythonhosted.org/packages/93/62/5e89cdfe04584cb7f4d36003ffa2936681b03ecc0754f8e969c2becb7e24/charset_normalizer-3.4.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b010a7a4fd316c3c484d482922d13044979e78d1861f0e0650423144c616a46a", size = 146123 }, { url = "https://files.pythonhosted.org/packages/a9/ac/ab729a15c516da2ab70a05f8722ecfccc3f04ed7a18e45c75bbbaa347d61/charset_normalizer-3.4.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4532bff1b8421fd0a320463030c7520f56a79c9024a4e88f01c537316019005a", size = 147943 }, { url = "https://files.pythonhosted.org/packages/03/d2/3f392f23f042615689456e9a274640c1d2e5dd1d52de36ab8f7955f8f050/charset_normalizer-3.4.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:d973f03c0cb71c5ed99037b870f2be986c3c05e63622c017ea9816881d2dd247", size = 142063 }, { url = "https://files.pythonhosted.org/packages/f2/e3/e20aae5e1039a2cd9b08d9205f52142329f887f8cf70da3650326670bddf/charset_normalizer-3.4.1-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:3a3bd0dcd373514dcec91c411ddb9632c0d7d92aed7093b8c3bbb6d69ca74408", size = 150578 }, { url = "https://files.pythonhosted.org/packages/8d/af/779ad72a4da0aed925e1139d458adc486e61076d7ecdcc09e610ea8678db/charset_normalizer-3.4.1-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:d9c3cdf5390dcd29aa8056d13e8e99526cda0305acc038b96b30352aff5ff2bb", size = 153629 }, { url = "https://files.pythonhosted.org/packages/c2/b6/7aa450b278e7aa92cf7732140bfd8be21f5f29d5bf334ae987c945276639/charset_normalizer-3.4.1-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:2bdfe3ac2e1bbe5b59a1a63721eb3b95fc9b6817ae4a46debbb4e11f6232428d", size = 150778 }, { url = "https://files.pythonhosted.org/packages/39/f4/d9f4f712d0951dcbfd42920d3db81b00dd23b6ab520419626f4023334056/charset_normalizer-3.4.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:eab677309cdb30d047996b36d34caeda1dc91149e4fdca0b1a039b3f79d9a807", size = 146453 }, { url = "https://files.pythonhosted.org/packages/49/2b/999d0314e4ee0cff3cb83e6bc9aeddd397eeed693edb4facb901eb8fbb69/charset_normalizer-3.4.1-cp310-cp310-win32.whl", hash = "sha256:c0429126cf75e16c4f0ad00ee0eae4242dc652290f940152ca8c75c3a4b6ee8f", size = 95479 }, { url = "https://files.pythonhosted.org/packages/2d/ce/3cbed41cff67e455a386fb5e5dd8906cdda2ed92fbc6297921f2e4419309/charset_normalizer-3.4.1-cp310-cp310-win_amd64.whl", hash = "sha256:9f0b8b1c6d84c8034a44893aba5e767bf9c7a211e313a9605d9c617d7083829f", size = 102790 }, { url = "https://files.pythonhosted.org/packages/72/80/41ef5d5a7935d2d3a773e3eaebf0a9350542f2cab4eac59a7a4741fbbbbe/charset_normalizer-3.4.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:8bfa33f4f2672964266e940dd22a195989ba31669bd84629f05fab3ef4e2d125", size = 194995 }, { url = "https://files.pythonhosted.org/packages/7a/28/0b9fefa7b8b080ec492110af6d88aa3dea91c464b17d53474b6e9ba5d2c5/charset_normalizer-3.4.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:28bf57629c75e810b6ae989f03c0828d64d6b26a5e205535585f96093e405ed1", size = 139471 }, { url = "https://files.pythonhosted.org/packages/71/64/d24ab1a997efb06402e3fc07317e94da358e2585165930d9d59ad45fcae2/charset_normalizer-3.4.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f08ff5e948271dc7e18a35641d2f11a4cd8dfd5634f55228b691e62b37125eb3", size = 149831 }, { url = "https://files.pythonhosted.org/packages/37/ed/be39e5258e198655240db5e19e0b11379163ad7070962d6b0c87ed2c4d39/charset_normalizer-3.4.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:234ac59ea147c59ee4da87a0c0f098e9c8d169f4dc2a159ef720f1a61bbe27cd", size = 142335 }, { url = "https://files.pythonhosted.org/packages/88/83/489e9504711fa05d8dde1574996408026bdbdbd938f23be67deebb5eca92/charset_normalizer-3.4.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fd4ec41f914fa74ad1b8304bbc634b3de73d2a0889bd32076342a573e0779e00", size = 143862 }, { url = "https://files.pythonhosted.org/packages/c6/c7/32da20821cf387b759ad24627a9aca289d2822de929b8a41b6241767b461/charset_normalizer-3.4.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:eea6ee1db730b3483adf394ea72f808b6e18cf3cb6454b4d86e04fa8c4327a12", size = 145673 }, { url = "https://files.pythonhosted.org/packages/68/85/f4288e96039abdd5aeb5c546fa20a37b50da71b5cf01e75e87f16cd43304/charset_normalizer-3.4.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:c96836c97b1238e9c9e3fe90844c947d5afbf4f4c92762679acfe19927d81d77", size = 140211 }, { url = "https://files.pythonhosted.org/packages/28/a3/a42e70d03cbdabc18997baf4f0227c73591a08041c149e710045c281f97b/charset_normalizer-3.4.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:4d86f7aff21ee58f26dcf5ae81a9addbd914115cdebcbb2217e4f0ed8982e146", size = 148039 }, { url = "https://files.pythonhosted.org/packages/85/e4/65699e8ab3014ecbe6f5c71d1a55d810fb716bbfd74f6283d5c2aa87febf/charset_normalizer-3.4.1-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:09b5e6733cbd160dcc09589227187e242a30a49ca5cefa5a7edd3f9d19ed53fd", size = 151939 }, { url = "https://files.pythonhosted.org/packages/b1/82/8e9fe624cc5374193de6860aba3ea8070f584c8565ee77c168ec13274bd2/charset_normalizer-3.4.1-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:5777ee0881f9499ed0f71cc82cf873d9a0ca8af166dfa0af8ec4e675b7df48e6", size = 149075 }, { url = "https://files.pythonhosted.org/packages/3d/7b/82865ba54c765560c8433f65e8acb9217cb839a9e32b42af4aa8e945870f/charset_normalizer-3.4.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:237bdbe6159cff53b4f24f397d43c6336c6b0b42affbe857970cefbb620911c8", size = 144340 }, { url = "https://files.pythonhosted.org/packages/b5/b6/9674a4b7d4d99a0d2df9b215da766ee682718f88055751e1e5e753c82db0/charset_normalizer-3.4.1-cp311-cp311-win32.whl", hash = "sha256:8417cb1f36cc0bc7eaba8ccb0e04d55f0ee52df06df3ad55259b9a323555fc8b", size = 95205 }, { url = "https://files.pythonhosted.org/packages/1e/ab/45b180e175de4402dcf7547e4fb617283bae54ce35c27930a6f35b6bef15/charset_normalizer-3.4.1-cp311-cp311-win_amd64.whl", hash = "sha256:d7f50a1f8c450f3925cb367d011448c39239bb3eb4117c36a6d354794de4ce76", size = 102441 }, { url = "https://files.pythonhosted.org/packages/0a/9a/dd1e1cdceb841925b7798369a09279bd1cf183cef0f9ddf15a3a6502ee45/charset_normalizer-3.4.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:73d94b58ec7fecbc7366247d3b0b10a21681004153238750bb67bd9012414545", size = 196105 }, { url = "https://files.pythonhosted.org/packages/d3/8c/90bfabf8c4809ecb648f39794cf2a84ff2e7d2a6cf159fe68d9a26160467/charset_normalizer-3.4.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dad3e487649f498dd991eeb901125411559b22e8d7ab25d3aeb1af367df5efd7", size = 140404 }, { url = "https://files.pythonhosted.org/packages/ad/8f/e410d57c721945ea3b4f1a04b74f70ce8fa800d393d72899f0a40526401f/charset_normalizer-3.4.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c30197aa96e8eed02200a83fba2657b4c3acd0f0aa4bdc9f6c1af8e8962e0757", size = 150423 }, { url = "https://files.pythonhosted.org/packages/f0/b8/e6825e25deb691ff98cf5c9072ee0605dc2acfca98af70c2d1b1bc75190d/charset_normalizer-3.4.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2369eea1ee4a7610a860d88f268eb39b95cb588acd7235e02fd5a5601773d4fa", size = 143184 }, { url = "https://files.pythonhosted.org/packages/3e/a2/513f6cbe752421f16d969e32f3583762bfd583848b763913ddab8d9bfd4f/charset_normalizer-3.4.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bc2722592d8998c870fa4e290c2eec2c1569b87fe58618e67d38b4665dfa680d", size = 145268 }, { url = "https://files.pythonhosted.org/packages/74/94/8a5277664f27c3c438546f3eb53b33f5b19568eb7424736bdc440a88a31f/charset_normalizer-3.4.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ffc9202a29ab3920fa812879e95a9e78b2465fd10be7fcbd042899695d75e616", size = 147601 }, { url = "https://files.pythonhosted.org/packages/7c/5f/6d352c51ee763623a98e31194823518e09bfa48be2a7e8383cf691bbb3d0/charset_normalizer-3.4.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:804a4d582ba6e5b747c625bf1255e6b1507465494a40a2130978bda7b932c90b", size = 141098 }, { url = "https://files.pythonhosted.org/packages/78/d4/f5704cb629ba5ab16d1d3d741396aec6dc3ca2b67757c45b0599bb010478/charset_normalizer-3.4.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:0f55e69f030f7163dffe9fd0752b32f070566451afe180f99dbeeb81f511ad8d", size = 149520 }, { url = "https://files.pythonhosted.org/packages/c5/96/64120b1d02b81785f222b976c0fb79a35875457fa9bb40827678e54d1bc8/charset_normalizer-3.4.1-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:c4c3e6da02df6fa1410a7680bd3f63d4f710232d3139089536310d027950696a", size = 152852 }, { url = "https://files.pythonhosted.org/packages/84/c9/98e3732278a99f47d487fd3468bc60b882920cef29d1fa6ca460a1fdf4e6/charset_normalizer-3.4.1-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:5df196eb874dae23dcfb968c83d4f8fdccb333330fe1fc278ac5ceeb101003a9", size = 150488 }, { url = "https://files.pythonhosted.org/packages/13/0e/9c8d4cb99c98c1007cc11eda969ebfe837bbbd0acdb4736d228ccaabcd22/charset_normalizer-3.4.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:e358e64305fe12299a08e08978f51fc21fac060dcfcddd95453eabe5b93ed0e1", size = 146192 }, { url = "https://files.pythonhosted.org/packages/b2/21/2b6b5b860781a0b49427309cb8670785aa543fb2178de875b87b9cc97746/charset_normalizer-3.4.1-cp312-cp312-win32.whl", hash = "sha256:9b23ca7ef998bc739bf6ffc077c2116917eabcc901f88da1b9856b210ef63f35", size = 95550 }, { url = "https://files.pythonhosted.org/packages/21/5b/1b390b03b1d16c7e382b561c5329f83cc06623916aab983e8ab9239c7d5c/charset_normalizer-3.4.1-cp312-cp312-win_amd64.whl", hash = "sha256:6ff8a4a60c227ad87030d76e99cd1698345d4491638dfa6673027c48b3cd395f", size = 102785 }, { url = "https://files.pythonhosted.org/packages/38/94/ce8e6f63d18049672c76d07d119304e1e2d7c6098f0841b51c666e9f44a0/charset_normalizer-3.4.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:aabfa34badd18f1da5ec1bc2715cadc8dca465868a4e73a0173466b688f29dda", size = 195698 }, { url = "https://files.pythonhosted.org/packages/24/2e/dfdd9770664aae179a96561cc6952ff08f9a8cd09a908f259a9dfa063568/charset_normalizer-3.4.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:22e14b5d70560b8dd51ec22863f370d1e595ac3d024cb8ad7d308b4cd95f8313", size = 140162 }, { url = "https://files.pythonhosted.org/packages/24/4e/f646b9093cff8fc86f2d60af2de4dc17c759de9d554f130b140ea4738ca6/charset_normalizer-3.4.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8436c508b408b82d87dc5f62496973a1805cd46727c34440b0d29d8a2f50a6c9", size = 150263 }, { url = "https://files.pythonhosted.org/packages/5e/67/2937f8d548c3ef6e2f9aab0f6e21001056f692d43282b165e7c56023e6dd/charset_normalizer-3.4.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2d074908e1aecee37a7635990b2c6d504cd4766c7bc9fc86d63f9c09af3fa11b", size = 142966 }, { url = "https://files.pythonhosted.org/packages/52/ed/b7f4f07de100bdb95c1756d3a4d17b90c1a3c53715c1a476f8738058e0fa/charset_normalizer-3.4.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:955f8851919303c92343d2f66165294848d57e9bba6cf6e3625485a70a038d11", size = 144992 }, { url = "https://files.pythonhosted.org/packages/96/2c/d49710a6dbcd3776265f4c923bb73ebe83933dfbaa841c5da850fe0fd20b/charset_normalizer-3.4.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:44ecbf16649486d4aebafeaa7ec4c9fed8b88101f4dd612dcaf65d5e815f837f", size = 147162 }, { url = "https://files.pythonhosted.org/packages/b4/41/35ff1f9a6bd380303dea55e44c4933b4cc3c4850988927d4082ada230273/charset_normalizer-3.4.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:0924e81d3d5e70f8126529951dac65c1010cdf117bb75eb02dd12339b57749dd", size = 140972 }, { url = "https://files.pythonhosted.org/packages/fb/43/c6a0b685fe6910d08ba971f62cd9c3e862a85770395ba5d9cad4fede33ab/charset_normalizer-3.4.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:2967f74ad52c3b98de4c3b32e1a44e32975e008a9cd2a8cc8966d6a5218c5cb2", size = 149095 }, { url = "https://files.pythonhosted.org/packages/4c/ff/a9a504662452e2d2878512115638966e75633519ec11f25fca3d2049a94a/charset_normalizer-3.4.1-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:c75cb2a3e389853835e84a2d8fb2b81a10645b503eca9bcb98df6b5a43eb8886", size = 152668 }, { url = "https://files.pythonhosted.org/packages/6c/71/189996b6d9a4b932564701628af5cee6716733e9165af1d5e1b285c530ed/charset_normalizer-3.4.1-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:09b26ae6b1abf0d27570633b2b078a2a20419c99d66fb2823173d73f188ce601", size = 150073 }, { url = "https://files.pythonhosted.org/packages/e4/93/946a86ce20790e11312c87c75ba68d5f6ad2208cfb52b2d6a2c32840d922/charset_normalizer-3.4.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:fa88b843d6e211393a37219e6a1c1df99d35e8fd90446f1118f4216e307e48cd", size = 145732 }, { url = "https://files.pythonhosted.org/packages/cd/e5/131d2fb1b0dddafc37be4f3a2fa79aa4c037368be9423061dccadfd90091/charset_normalizer-3.4.1-cp313-cp313-win32.whl", hash = "sha256:eb8178fe3dba6450a3e024e95ac49ed3400e506fd4e9e5c32d30adda88cbd407", size = 95391 }, { url = "https://files.pythonhosted.org/packages/27/f2/4f9a69cc7712b9b5ad8fdb87039fd89abba997ad5cbe690d1835d40405b0/charset_normalizer-3.4.1-cp313-cp313-win_amd64.whl", hash = "sha256:b1ac5992a838106edb89654e0aebfc24f5848ae2547d22c2c3f66454daa11971", size = 102702 }, { url = "https://files.pythonhosted.org/packages/7f/c0/b913f8f02836ed9ab32ea643c6fe4d3325c3d8627cf6e78098671cafff86/charset_normalizer-3.4.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:b97e690a2118911e39b4042088092771b4ae3fc3aa86518f84b8cf6888dbdb41", size = 197867 }, { url = "https://files.pythonhosted.org/packages/0f/6c/2bee440303d705b6fb1e2ec789543edec83d32d258299b16eed28aad48e0/charset_normalizer-3.4.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:78baa6d91634dfb69ec52a463534bc0df05dbd546209b79a3880a34487f4b84f", size = 141385 }, { url = "https://files.pythonhosted.org/packages/3d/04/cb42585f07f6f9fd3219ffb6f37d5a39b4fd2db2355b23683060029c35f7/charset_normalizer-3.4.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1a2bc9f351a75ef49d664206d51f8e5ede9da246602dc2d2726837620ea034b2", size = 151367 }, { url = "https://files.pythonhosted.org/packages/54/54/2412a5b093acb17f0222de007cc129ec0e0df198b5ad2ce5699355269dfe/charset_normalizer-3.4.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:75832c08354f595c760a804588b9357d34ec00ba1c940c15e31e96d902093770", size = 143928 }, { url = "https://files.pythonhosted.org/packages/5a/6d/e2773862b043dcf8a221342954f375392bb2ce6487bcd9f2c1b34e1d6781/charset_normalizer-3.4.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0af291f4fe114be0280cdd29d533696a77b5b49cfde5467176ecab32353395c4", size = 146203 }, { url = "https://files.pythonhosted.org/packages/b9/f8/ca440ef60d8f8916022859885f231abb07ada3c347c03d63f283bec32ef5/charset_normalizer-3.4.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0167ddc8ab6508fe81860a57dd472b2ef4060e8d378f0cc555707126830f2537", size = 148082 }, { url = "https://files.pythonhosted.org/packages/04/d2/42fd330901aaa4b805a1097856c2edf5095e260a597f65def493f4b8c833/charset_normalizer-3.4.1-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:2a75d49014d118e4198bcee5ee0a6f25856b29b12dbf7cd012791f8a6cc5c496", size = 142053 }, { url = "https://files.pythonhosted.org/packages/9e/af/3a97a4fa3c53586f1910dadfc916e9c4f35eeada36de4108f5096cb7215f/charset_normalizer-3.4.1-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:363e2f92b0f0174b2f8238240a1a30142e3db7b957a5dd5689b0e75fb717cc78", size = 150625 }, { url = "https://files.pythonhosted.org/packages/26/ae/23d6041322a3556e4da139663d02fb1b3c59a23ab2e2b56432bd2ad63ded/charset_normalizer-3.4.1-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:ab36c8eb7e454e34e60eb55ca5d241a5d18b2c6244f6827a30e451c42410b5f7", size = 153549 }, { url = "https://files.pythonhosted.org/packages/94/22/b8f2081c6a77cb20d97e57e0b385b481887aa08019d2459dc2858ed64871/charset_normalizer-3.4.1-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:4c0907b1928a36d5a998d72d64d8eaa7244989f7aaaf947500d3a800c83a3fd6", size = 150945 }, { url = "https://files.pythonhosted.org/packages/c7/0b/c5ec5092747f801b8b093cdf5610e732b809d6cb11f4c51e35fc28d1d389/charset_normalizer-3.4.1-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:04432ad9479fa40ec0f387795ddad4437a2b50417c69fa275e212933519ff294", size = 146595 }, { url = "https://files.pythonhosted.org/packages/0c/5a/0b59704c38470df6768aa154cc87b1ac7c9bb687990a1559dc8765e8627e/charset_normalizer-3.4.1-cp39-cp39-win32.whl", hash = "sha256:3bed14e9c89dcb10e8f3a29f9ccac4955aebe93c71ae803af79265c9ca5644c5", size = 95453 }, { url = "https://files.pythonhosted.org/packages/85/2d/a9790237cb4d01a6d57afadc8573c8b73c609ade20b80f4cda30802009ee/charset_normalizer-3.4.1-cp39-cp39-win_amd64.whl", hash = "sha256:49402233c892a461407c512a19435d1ce275543138294f7ef013f0b63d5d3765", size = 102811 }, { url = "https://files.pythonhosted.org/packages/0e/f6/65ecc6878a89bb1c23a086ea335ad4bf21a588990c3f535a227b9eea9108/charset_normalizer-3.4.1-py3-none-any.whl", hash = "sha256:d98b1668f06378c6dbefec3b92299716b931cd4e6061f3c875a71ced1780ab85", size = 49767 }, ] [[package]] name = "click" version = "8.1.8" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "colorama", marker = "sys_platform == 'win32'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/b9/2e/0090cbf739cee7d23781ad4b89a9894a41538e4fcf4c31dcdd705b78eb8b/click-8.1.8.tar.gz", hash = "sha256:ed53c9d8990d83c2a27deae68e4ee337473f6330c040a31d4225c9574d16096a", size = 226593 } wheels = [ { url = "https://files.pythonhosted.org/packages/7e/d4/7ebdbd03970677812aac39c869717059dbb71a4cfc033ca6e5221787892c/click-8.1.8-py3-none-any.whl", hash = "sha256:63c132bbbed01578a06712a2d1f497bb62d9c1c0d329b7903a866228027263b2", size = 98188 }, ] [[package]] name = "colorama" version = "0.4.6" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/d8/53/6f443c9a4a8358a93a6792e2acffb9d9d5cb0a5cfd8802644b7b1c9a02e4/colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44", size = 27697 } wheels = [ { url = "https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6", size = 25335 }, ] [[package]] name = "cookiecutter" version = "2.6.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "arrow" }, { name = "binaryornot" }, { name = "click" }, { name = "jinja2" }, { name = "python-slugify" }, { name = "pyyaml" }, { name = "requests" }, { name = "rich" }, ] sdist = { url = "https://files.pythonhosted.org/packages/52/17/9f2cd228eb949a91915acd38d3eecdc9d8893dde353b603f0db7e9f6be55/cookiecutter-2.6.0.tar.gz", hash = "sha256:db21f8169ea4f4fdc2408d48ca44859349de2647fbe494a9d6c3edfc0542c21c", size = 158767 } wheels = [ { url = "https://files.pythonhosted.org/packages/b6/d9/0137658a353168ffa9d0fc14b812d3834772040858ddd1cb6eeaf09f7a44/cookiecutter-2.6.0-py3-none-any.whl", hash = "sha256:a54a8e37995e4ed963b3e82831072d1ad4b005af736bb17b99c2cbd9d41b6e2d", size = 39177 }, ] [[package]] name = "coverage" version = "7.6.10" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/84/ba/ac14d281f80aab516275012e8875991bb06203957aa1e19950139238d658/coverage-7.6.10.tar.gz", hash = "sha256:7fb105327c8f8f0682e29843e2ff96af9dcbe5bab8eeb4b398c6a33a16d80a23", size = 803868 } wheels = [ { url = "https://files.pythonhosted.org/packages/c5/12/2a2a923edf4ddabdffed7ad6da50d96a5c126dae7b80a33df7310e329a1e/coverage-7.6.10-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:5c912978f7fbf47ef99cec50c4401340436d200d41d714c7a4766f377c5b7b78", size = 207982 }, { url = "https://files.pythonhosted.org/packages/ca/49/6985dbca9c7be3f3cb62a2e6e492a0c88b65bf40579e16c71ae9c33c6b23/coverage-7.6.10-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:a01ec4af7dfeb96ff0078ad9a48810bb0cc8abcb0115180c6013a6b26237626c", size = 208414 }, { url = "https://files.pythonhosted.org/packages/35/93/287e8f1d1ed2646f4e0b2605d14616c9a8a2697d0d1b453815eb5c6cebdb/coverage-7.6.10-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a3b204c11e2b2d883946fe1d97f89403aa1811df28ce0447439178cc7463448a", size = 236860 }, { url = "https://files.pythonhosted.org/packages/de/e1/cfdb5627a03567a10031acc629b75d45a4ca1616e54f7133ca1fa366050a/coverage-7.6.10-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:32ee6d8491fcfc82652a37109f69dee9a830e9379166cb73c16d8dc5c2915165", size = 234758 }, { url = "https://files.pythonhosted.org/packages/6d/85/fc0de2bcda3f97c2ee9fe8568f7d48f7279e91068958e5b2cc19e0e5f600/coverage-7.6.10-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:675cefc4c06e3b4c876b85bfb7c59c5e2218167bbd4da5075cbe3b5790a28988", size = 235920 }, { url = "https://files.pythonhosted.org/packages/79/73/ef4ea0105531506a6f4cf4ba571a214b14a884630b567ed65b3d9c1975e1/coverage-7.6.10-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:f4f620668dbc6f5e909a0946a877310fb3d57aea8198bde792aae369ee1c23b5", size = 234986 }, { url = "https://files.pythonhosted.org/packages/c6/4d/75afcfe4432e2ad0405c6f27adeb109ff8976c5e636af8604f94f29fa3fc/coverage-7.6.10-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:4eea95ef275de7abaef630c9b2c002ffbc01918b726a39f5a4353916ec72d2f3", size = 233446 }, { url = "https://files.pythonhosted.org/packages/86/5b/efee56a89c16171288cafff022e8af44f8f94075c2d8da563c3935212871/coverage-7.6.10-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:e2f0280519e42b0a17550072861e0bc8a80a0870de260f9796157d3fca2733c5", size = 234566 }, { url = "https://files.pythonhosted.org/packages/f2/db/67770cceb4a64d3198bf2aa49946f411b85ec6b0a9b489e61c8467a4253b/coverage-7.6.10-cp310-cp310-win32.whl", hash = "sha256:bc67deb76bc3717f22e765ab3e07ee9c7a5e26b9019ca19a3b063d9f4b874244", size = 210675 }, { url = "https://files.pythonhosted.org/packages/8d/27/e8bfc43f5345ec2c27bc8a1fa77cdc5ce9dcf954445e11f14bb70b889d14/coverage-7.6.10-cp310-cp310-win_amd64.whl", hash = "sha256:0f460286cb94036455e703c66988851d970fdfd8acc2a1122ab7f4f904e4029e", size = 211518 }, { url = "https://files.pythonhosted.org/packages/85/d2/5e175fcf6766cf7501a8541d81778fd2f52f4870100e791f5327fd23270b/coverage-7.6.10-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:ea3c8f04b3e4af80e17bab607c386a830ffc2fb88a5484e1df756478cf70d1d3", size = 208088 }, { url = "https://files.pythonhosted.org/packages/4b/6f/06db4dc8fca33c13b673986e20e466fd936235a6ec1f0045c3853ac1b593/coverage-7.6.10-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:507a20fc863cae1d5720797761b42d2d87a04b3e5aeb682ef3b7332e90598f43", size = 208536 }, { url = "https://files.pythonhosted.org/packages/0d/62/c6a0cf80318c1c1af376d52df444da3608eafc913b82c84a4600d8349472/coverage-7.6.10-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d37a84878285b903c0fe21ac8794c6dab58150e9359f1aaebbeddd6412d53132", size = 240474 }, { url = "https://files.pythonhosted.org/packages/a3/59/750adafc2e57786d2e8739a46b680d4fb0fbc2d57fbcb161290a9f1ecf23/coverage-7.6.10-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a534738b47b0de1995f85f582d983d94031dffb48ab86c95bdf88dc62212142f", size = 237880 }, { url = "https://files.pythonhosted.org/packages/2c/f8/ef009b3b98e9f7033c19deb40d629354aab1d8b2d7f9cfec284dbedf5096/coverage-7.6.10-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0d7a2bf79378d8fb8afaa994f91bfd8215134f8631d27eba3e0e2c13546ce994", size = 239750 }, { url = "https://files.pythonhosted.org/packages/a6/e2/6622f3b70f5f5b59f705e680dae6db64421af05a5d1e389afd24dae62e5b/coverage-7.6.10-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:6713ba4b4ebc330f3def51df1d5d38fad60b66720948112f114968feb52d3f99", size = 238642 }, { url = "https://files.pythonhosted.org/packages/2d/10/57ac3f191a3c95c67844099514ff44e6e19b2915cd1c22269fb27f9b17b6/coverage-7.6.10-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:ab32947f481f7e8c763fa2c92fd9f44eeb143e7610c4ca9ecd6a36adab4081bd", size = 237266 }, { url = "https://files.pythonhosted.org/packages/ee/2d/7016f4ad9d553cabcb7333ed78ff9d27248ec4eba8dd21fa488254dff894/coverage-7.6.10-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:7bbd8c8f1b115b892e34ba66a097b915d3871db7ce0e6b9901f462ff3a975377", size = 238045 }, { url = "https://files.pythonhosted.org/packages/a7/fe/45af5c82389a71e0cae4546413266d2195c3744849669b0bab4b5f2c75da/coverage-7.6.10-cp311-cp311-win32.whl", hash = "sha256:299e91b274c5c9cdb64cbdf1b3e4a8fe538a7a86acdd08fae52301b28ba297f8", size = 210647 }, { url = "https://files.pythonhosted.org/packages/db/11/3f8e803a43b79bc534c6a506674da9d614e990e37118b4506faf70d46ed6/coverage-7.6.10-cp311-cp311-win_amd64.whl", hash = "sha256:489a01f94aa581dbd961f306e37d75d4ba16104bbfa2b0edb21d29b73be83609", size = 211508 }, { url = "https://files.pythonhosted.org/packages/86/77/19d09ea06f92fdf0487499283b1b7af06bc422ea94534c8fe3a4cd023641/coverage-7.6.10-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:27c6e64726b307782fa5cbe531e7647aee385a29b2107cd87ba7c0105a5d3853", size = 208281 }, { url = "https://files.pythonhosted.org/packages/b6/67/5479b9f2f99fcfb49c0d5cf61912a5255ef80b6e80a3cddba39c38146cf4/coverage-7.6.10-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:c56e097019e72c373bae32d946ecf9858fda841e48d82df7e81c63ac25554078", size = 208514 }, { url = "https://files.pythonhosted.org/packages/15/d1/febf59030ce1c83b7331c3546d7317e5120c5966471727aa7ac157729c4b/coverage-7.6.10-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c7827a5bc7bdb197b9e066cdf650b2887597ad124dd99777332776f7b7c7d0d0", size = 241537 }, { url = "https://files.pythonhosted.org/packages/4b/7e/5ac4c90192130e7cf8b63153fe620c8bfd9068f89a6d9b5f26f1550f7a26/coverage-7.6.10-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:204a8238afe787323a8b47d8be4df89772d5c1e4651b9ffa808552bdf20e1d50", size = 238572 }, { url = "https://files.pythonhosted.org/packages/dc/03/0334a79b26ecf59958f2fe9dd1f5ab3e2f88db876f5071933de39af09647/coverage-7.6.10-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e67926f51821b8e9deb6426ff3164870976fe414d033ad90ea75e7ed0c2e5022", size = 240639 }, { url = "https://files.pythonhosted.org/packages/d7/45/8a707f23c202208d7b286d78ad6233f50dcf929319b664b6cc18a03c1aae/coverage-7.6.10-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:e78b270eadb5702938c3dbe9367f878249b5ef9a2fcc5360ac7bff694310d17b", size = 240072 }, { url = "https://files.pythonhosted.org/packages/66/02/603ce0ac2d02bc7b393279ef618940b4a0535b0868ee791140bda9ecfa40/coverage-7.6.10-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:714f942b9c15c3a7a5fe6876ce30af831c2ad4ce902410b7466b662358c852c0", size = 238386 }, { url = "https://files.pythonhosted.org/packages/04/62/4e6887e9be060f5d18f1dd58c2838b2d9646faf353232dec4e2d4b1c8644/coverage-7.6.10-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:abb02e2f5a3187b2ac4cd46b8ced85a0858230b577ccb2c62c81482ca7d18852", size = 240054 }, { url = "https://files.pythonhosted.org/packages/5c/74/83ae4151c170d8bd071924f212add22a0e62a7fe2b149edf016aeecad17c/coverage-7.6.10-cp312-cp312-win32.whl", hash = "sha256:55b201b97286cf61f5e76063f9e2a1d8d2972fc2fcfd2c1272530172fd28c359", size = 210904 }, { url = "https://files.pythonhosted.org/packages/c3/54/de0893186a221478f5880283119fc40483bc460b27c4c71d1b8bba3474b9/coverage-7.6.10-cp312-cp312-win_amd64.whl", hash = "sha256:e4ae5ac5e0d1e4edfc9b4b57b4cbecd5bc266a6915c500f358817a8496739247", size = 211692 }, { url = "https://files.pythonhosted.org/packages/25/6d/31883d78865529257bf847df5789e2ae80e99de8a460c3453dbfbe0db069/coverage-7.6.10-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:05fca8ba6a87aabdd2d30d0b6c838b50510b56cdcfc604d40760dae7153b73d9", size = 208308 }, { url = "https://files.pythonhosted.org/packages/70/22/3f2b129cc08de00c83b0ad6252e034320946abfc3e4235c009e57cfeee05/coverage-7.6.10-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:9e80eba8801c386f72e0712a0453431259c45c3249f0009aff537a517b52942b", size = 208565 }, { url = "https://files.pythonhosted.org/packages/97/0a/d89bc2d1cc61d3a8dfe9e9d75217b2be85f6c73ebf1b9e3c2f4e797f4531/coverage-7.6.10-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a372c89c939d57abe09e08c0578c1d212e7a678135d53aa16eec4430adc5e690", size = 241083 }, { url = "https://files.pythonhosted.org/packages/4c/81/6d64b88a00c7a7aaed3a657b8eaa0931f37a6395fcef61e53ff742b49c97/coverage-7.6.10-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ec22b5e7fe7a0fa8509181c4aac1db48f3dd4d3a566131b313d1efc102892c18", size = 238235 }, { url = "https://files.pythonhosted.org/packages/9a/0b/7797d4193f5adb4b837207ed87fecf5fc38f7cc612b369a8e8e12d9fa114/coverage-7.6.10-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:26bcf5c4df41cad1b19c84af71c22cbc9ea9a547fc973f1f2cc9a290002c8b3c", size = 240220 }, { url = "https://files.pythonhosted.org/packages/65/4d/6f83ca1bddcf8e51bf8ff71572f39a1c73c34cf50e752a952c34f24d0a60/coverage-7.6.10-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:4e4630c26b6084c9b3cb53b15bd488f30ceb50b73c35c5ad7871b869cb7365fd", size = 239847 }, { url = "https://files.pythonhosted.org/packages/30/9d/2470df6aa146aff4c65fee0f87f58d2164a67533c771c9cc12ffcdb865d5/coverage-7.6.10-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:2396e8116db77789f819d2bc8a7e200232b7a282c66e0ae2d2cd84581a89757e", size = 237922 }, { url = "https://files.pythonhosted.org/packages/08/dd/723fef5d901e6a89f2507094db66c091449c8ba03272861eaefa773ad95c/coverage-7.6.10-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:79109c70cc0882e4d2d002fe69a24aa504dec0cc17169b3c7f41a1d341a73694", size = 239783 }, { url = "https://files.pythonhosted.org/packages/3d/f7/64d3298b2baf261cb35466000628706ce20a82d42faf9b771af447cd2b76/coverage-7.6.10-cp313-cp313-win32.whl", hash = "sha256:9e1747bab246d6ff2c4f28b4d186b205adced9f7bd9dc362051cc37c4a0c7bd6", size = 210965 }, { url = "https://files.pythonhosted.org/packages/d5/58/ec43499a7fc681212fe7742fe90b2bc361cdb72e3181ace1604247a5b24d/coverage-7.6.10-cp313-cp313-win_amd64.whl", hash = "sha256:254f1a3b1eef5f7ed23ef265eaa89c65c8c5b6b257327c149db1ca9d4a35f25e", size = 211719 }, { url = "https://files.pythonhosted.org/packages/ab/c9/f2857a135bcff4330c1e90e7d03446b036b2363d4ad37eb5e3a47bbac8a6/coverage-7.6.10-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:2ccf240eb719789cedbb9fd1338055de2761088202a9a0b73032857e53f612fe", size = 209050 }, { url = "https://files.pythonhosted.org/packages/aa/b3/f840e5bd777d8433caa9e4a1eb20503495709f697341ac1a8ee6a3c906ad/coverage-7.6.10-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:0c807ca74d5a5e64427c8805de15b9ca140bba13572d6d74e262f46f50b13273", size = 209321 }, { url = "https://files.pythonhosted.org/packages/85/7d/125a5362180fcc1c03d91850fc020f3831d5cda09319522bcfa6b2b70be7/coverage-7.6.10-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2bcfa46d7709b5a7ffe089075799b902020b62e7ee56ebaed2f4bdac04c508d8", size = 252039 }, { url = "https://files.pythonhosted.org/packages/a9/9c/4358bf3c74baf1f9bddd2baf3756b54c07f2cfd2535f0a47f1e7757e54b3/coverage-7.6.10-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4e0de1e902669dccbf80b0415fb6b43d27edca2fbd48c74da378923b05316098", size = 247758 }, { url = "https://files.pythonhosted.org/packages/cf/c7/de3eb6fc5263b26fab5cda3de7a0f80e317597a4bad4781859f72885f300/coverage-7.6.10-cp313-cp313t-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3f7b444c42bbc533aaae6b5a2166fd1a797cdb5eb58ee51a92bee1eb94a1e1cb", size = 250119 }, { url = "https://files.pythonhosted.org/packages/3e/e6/43de91f8ba2ec9140c6a4af1102141712949903dc732cf739167cfa7a3bc/coverage-7.6.10-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:b330368cb99ef72fcd2dc3ed260adf67b31499584dc8a20225e85bfe6f6cfed0", size = 249597 }, { url = "https://files.pythonhosted.org/packages/08/40/61158b5499aa2adf9e37bc6d0117e8f6788625b283d51e7e0c53cf340530/coverage-7.6.10-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:9a7cfb50515f87f7ed30bc882f68812fd98bc2852957df69f3003d22a2aa0abf", size = 247473 }, { url = "https://files.pythonhosted.org/packages/50/69/b3f2416725621e9f112e74e8470793d5b5995f146f596f133678a633b77e/coverage-7.6.10-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:6f93531882a5f68c28090f901b1d135de61b56331bba82028489bc51bdd818d2", size = 248737 }, { url = "https://files.pythonhosted.org/packages/3c/6e/fe899fb937657db6df31cc3e61c6968cb56d36d7326361847440a430152e/coverage-7.6.10-cp313-cp313t-win32.whl", hash = "sha256:89d76815a26197c858f53c7f6a656686ec392b25991f9e409bcef020cd532312", size = 211611 }, { url = "https://files.pythonhosted.org/packages/1c/55/52f5e66142a9d7bc93a15192eba7a78513d2abf6b3558d77b4ca32f5f424/coverage-7.6.10-cp313-cp313t-win_amd64.whl", hash = "sha256:54a5f0f43950a36312155dae55c505a76cd7f2b12d26abeebbe7a0b36dbc868d", size = 212781 }, { url = "https://files.pythonhosted.org/packages/40/41/473617aadf9a1c15bc2d56be65d90d7c29bfa50a957a67ef96462f7ebf8e/coverage-7.6.10-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:656c82b8a0ead8bba147de9a89bda95064874c91a3ed43a00e687f23cc19d53a", size = 207978 }, { url = "https://files.pythonhosted.org/packages/10/f6/480586607768b39a30e6910a3c4522139094ac0f1677028e1f4823688957/coverage-7.6.10-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:ccc2b70a7ed475c68ceb548bf69cec1e27305c1c2606a5eb7c3afff56a1b3b27", size = 208415 }, { url = "https://files.pythonhosted.org/packages/f1/af/439bb760f817deff6f4d38fe7da08d9dd7874a560241f1945bc3b4446550/coverage-7.6.10-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a5e37dc41d57ceba70956fa2fc5b63c26dba863c946ace9705f8eca99daecdc4", size = 236452 }, { url = "https://files.pythonhosted.org/packages/d0/13/481f4ceffcabe29ee2332e60efb52e4694f54a402f3ada2bcec10bb32e43/coverage-7.6.10-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0aa9692b4fdd83a4647eeb7db46410ea1322b5ed94cd1715ef09d1d5922ba87f", size = 234374 }, { url = "https://files.pythonhosted.org/packages/c5/59/4607ea9d6b1b73e905c7656da08d0b00cdf6e59f2293ec259e8914160025/coverage-7.6.10-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:aa744da1820678b475e4ba3dfd994c321c5b13381d1041fe9c608620e6676e25", size = 235505 }, { url = "https://files.pythonhosted.org/packages/85/60/d66365723b9b7f29464b11d024248ed3523ce5aab958e4ad8c43f3f4148b/coverage-7.6.10-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:c0b1818063dc9e9d838c09e3a473c1422f517889436dd980f5d721899e66f315", size = 234616 }, { url = "https://files.pythonhosted.org/packages/74/f8/2cf7a38e7d81b266f47dfcf137fecd8fa66c7bdbd4228d611628d8ca3437/coverage-7.6.10-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:59af35558ba08b758aec4d56182b222976330ef8d2feacbb93964f576a7e7a90", size = 233099 }, { url = "https://files.pythonhosted.org/packages/50/2b/bff6c1c6b63c4396ea7ecdbf8db1788b46046c681b8fcc6ec77db9f4ea49/coverage-7.6.10-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:7ed2f37cfce1ce101e6dffdfd1c99e729dd2ffc291d02d3e2d0af8b53d13840d", size = 234089 }, { url = "https://files.pythonhosted.org/packages/bf/b5/baace1c754d546a67779358341aa8d2f7118baf58cac235db457e1001d1b/coverage-7.6.10-cp39-cp39-win32.whl", hash = "sha256:4bcc276261505d82f0ad426870c3b12cb177752834a633e737ec5ee79bbdff18", size = 210701 }, { url = "https://files.pythonhosted.org/packages/b1/bf/9e1e95b8b20817398ecc5a1e8d3e05ff404e1b9fb2185cd71561698fe2a2/coverage-7.6.10-cp39-cp39-win_amd64.whl", hash = "sha256:457574f4599d2b00f7f637a0700a6422243b3565509457b2dbd3f50703e11f59", size = 211482 }, { url = "https://files.pythonhosted.org/packages/a1/70/de81bfec9ed38a64fc44a77c7665e20ca507fc3265597c28b0d989e4082e/coverage-7.6.10-pp39.pp310-none-any.whl", hash = "sha256:fd34e7b3405f0cc7ab03d54a334c17a9e802897580d964bd8c2001f4b9fd488f", size = 200223 }, ] [package.optional-dependencies] toml = [ { name = "tomli", marker = "python_full_version <= '3.11'" }, ] [[package]] name = "cruft" version = "2.16.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "click" }, { name = "cookiecutter" }, { name = "gitpython" }, { name = "toml", marker = "python_full_version < '3.11'" }, { name = "typer" }, ] sdist = { url = "https://files.pythonhosted.org/packages/d1/7e/0e20012f2aa156e5d6a70483a8d90accb7ed4966dddb0c58987d9f6eba12/cruft-2.16.0.tar.gz", hash = "sha256:184662853fbc1c16c0137fe0e9444e0cbe95e40362f5ebb2d9fae33d9223e73f", size = 678333 } wheels = [ { url = "https://files.pythonhosted.org/packages/c9/76/1e88cda6ba47b593fcea24acce8070bb7cc5780c49f828b7b47c212bf62c/cruft-2.16.0-py3-none-any.whl", hash = "sha256:96adb81f814300a9db0fca690eaa063547f5d3c25f486ac0a366cf8da5cdfb79", size = 26635 }, ] [[package]] name = "cryptography" version = "44.0.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "cffi", marker = "platform_python_implementation != 'PyPy'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/91/4c/45dfa6829acffa344e3967d6006ee4ae8be57af746ae2eba1c431949b32c/cryptography-44.0.0.tar.gz", hash = "sha256:cd4e834f340b4293430701e772ec543b0fbe6c2dea510a5286fe0acabe153a02", size = 710657 } wheels = [ { url = "https://files.pythonhosted.org/packages/7e/5b/3759e30a103144e29632e7cb72aec28cedc79e514b2ea8896bb17163c19b/cryptography-44.0.0-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b15492a11f9e1b62ba9d73c210e2416724633167de94607ec6069ef724fad092", size = 3922710 }, { url = "https://files.pythonhosted.org/packages/5f/58/3b14bf39f1a0cfd679e753e8647ada56cddbf5acebffe7db90e184c76168/cryptography-44.0.0-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:831c3c4d0774e488fdc83a1923b49b9957d33287de923d58ebd3cec47a0ae43f", size = 4137546 }, { url = "https://files.pythonhosted.org/packages/98/65/13d9e76ca19b0ba5603d71ac8424b5694415b348e719db277b5edc985ff5/cryptography-44.0.0-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:761817a3377ef15ac23cd7834715081791d4ec77f9297ee694ca1ee9c2c7e5eb", size = 3915420 }, { url = "https://files.pythonhosted.org/packages/b1/07/40fe09ce96b91fc9276a9ad272832ead0fddedcba87f1190372af8e3039c/cryptography-44.0.0-cp37-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:3c672a53c0fb4725a29c303be906d3c1fa99c32f58abe008a82705f9ee96f40b", size = 4154498 }, { url = "https://files.pythonhosted.org/packages/75/ea/af65619c800ec0a7e4034207aec543acdf248d9bffba0533342d1bd435e1/cryptography-44.0.0-cp37-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:4ac4c9f37eba52cb6fbeaf5b59c152ea976726b865bd4cf87883a7e7006cc543", size = 3932569 }, { url = "https://files.pythonhosted.org/packages/c7/af/d1deb0c04d59612e3d5e54203159e284d3e7a6921e565bb0eeb6269bdd8a/cryptography-44.0.0-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:ed3534eb1090483c96178fcb0f8893719d96d5274dfde98aa6add34614e97c8e", size = 4016721 }, { url = "https://files.pythonhosted.org/packages/bd/69/7ca326c55698d0688db867795134bdfac87136b80ef373aaa42b225d6dd5/cryptography-44.0.0-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:f3f6fdfa89ee2d9d496e2c087cebef9d4fcbb0ad63c40e821b39f74bf48d9c5e", size = 4240915 }, { url = "https://files.pythonhosted.org/packages/1a/07/5f165b6c65696ef75601b781a280fc3b33f1e0cd6aa5a92d9fb96c410e97/cryptography-44.0.0-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1923cb251c04be85eec9fda837661c67c1049063305d6be5721643c22dd4e2b7", size = 3922613 }, { url = "https://files.pythonhosted.org/packages/28/34/6b3ac1d80fc174812486561cf25194338151780f27e438526f9c64e16869/cryptography-44.0.0-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:404fdc66ee5f83a1388be54300ae978b2efd538018de18556dde92575e05defc", size = 4137925 }, { url = "https://files.pythonhosted.org/packages/d0/c7/c656eb08fd22255d21bc3129625ed9cd5ee305f33752ef2278711b3fa98b/cryptography-44.0.0-cp39-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:c5eb858beed7835e5ad1faba59e865109f3e52b3783b9ac21e7e47dc5554e289", size = 3915417 }, { url = "https://files.pythonhosted.org/packages/ef/82/72403624f197af0db6bac4e58153bc9ac0e6020e57234115db9596eee85d/cryptography-44.0.0-cp39-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:f53c2c87e0fb4b0c00fa9571082a057e37690a8f12233306161c8f4b819960b7", size = 4155160 }, { url = "https://files.pythonhosted.org/packages/a2/cd/2f3c440913d4329ade49b146d74f2e9766422e1732613f57097fea61f344/cryptography-44.0.0-cp39-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:9e6fc8a08e116fb7c7dd1f040074c9d7b51d74a8ea40d4df2fc7aa08b76b9e6c", size = 3932331 }, { url = "https://files.pythonhosted.org/packages/7f/df/8be88797f0a1cca6e255189a57bb49237402b1880d6e8721690c5603ac23/cryptography-44.0.0-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:d2436114e46b36d00f8b72ff57e598978b37399d2786fd39793c36c6d5cb1c64", size = 4017372 }, { url = "https://files.pythonhosted.org/packages/af/36/5ccc376f025a834e72b8e52e18746b927f34e4520487098e283a719c205e/cryptography-44.0.0-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:a01956ddfa0a6790d594f5b34fc1bfa6098aca434696a03cfdbe469b8ed79285", size = 4239657 }, { url = "https://files.pythonhosted.org/packages/1a/aa/ba8a7467c206cb7b62f09b4168da541b5109838627f582843bbbe0235e8e/cryptography-44.0.0-pp310-pypy310_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:f677e1268c4e23420c3acade68fac427fffcb8d19d7df95ed7ad17cdef8404f4", size = 3850615 }, { url = "https://files.pythonhosted.org/packages/89/fa/b160e10a64cc395d090105be14f399b94e617c879efd401188ce0fea39ee/cryptography-44.0.0-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:f5e7cb1e5e56ca0933b4873c0220a78b773b24d40d186b6738080b73d3d0a756", size = 4081622 }, { url = "https://files.pythonhosted.org/packages/47/8f/20ff0656bb0cf7af26ec1d01f780c5cfbaa7666736063378c5f48558b515/cryptography-44.0.0-pp310-pypy310_pp73-manylinux_2_34_aarch64.whl", hash = "sha256:8b3e6eae66cf54701ee7d9c83c30ac0a1e3fa17be486033000f2a73a12ab507c", size = 3867546 }, { url = "https://files.pythonhosted.org/packages/38/d9/28edf32ee2fcdca587146bcde90102a7319b2f2c690edfa627e46d586050/cryptography-44.0.0-pp310-pypy310_pp73-manylinux_2_34_x86_64.whl", hash = "sha256:be4ce505894d15d5c5037167ffb7f0ae90b7be6f2a98f9a5c3442395501c32fa", size = 4090937 }, ] [[package]] name = "decorator" version = "5.1.1" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/66/0c/8d907af351aa16b42caae42f9d6aa37b900c67308052d10fdce809f8d952/decorator-5.1.1.tar.gz", hash = "sha256:637996211036b6385ef91435e4fae22989472f9d571faba8927ba8253acbc330", size = 35016 } wheels = [ { url = "https://files.pythonhosted.org/packages/d5/50/83c593b07763e1161326b3b8c6686f0f4b0f24d5526546bee538c89837d6/decorator-5.1.1-py3-none-any.whl", hash = "sha256:b8c3f85900b9dc423225913c5aace94729fe1fa9763b38939a95226f02d37186", size = 9073 }, ] [[package]] name = "defusedxml" version = "0.7.1" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/0f/d5/c66da9b79e5bdb124974bfe172b4daf3c984ebd9c2a06e2b8a4dc7331c72/defusedxml-0.7.1.tar.gz", hash = "sha256:1bb3032db185915b62d7c6209c5a8792be6a32ab2fedacc84e01b52c51aa3e69", size = 75520 } wheels = [ { url = "https://files.pythonhosted.org/packages/07/6c/aa3f2f849e01cb6a001cd8554a88d4c77c5c1a31c95bdf1cf9301e6d9ef4/defusedxml-0.7.1-py2.py3-none-any.whl", hash = "sha256:a352e7e428770286cc899e2542b6cdaedb2b4953ff269a210103ec58f6198a61", size = 25604 }, ] [[package]] name = "distlib" version = "0.3.9" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/0d/dd/1bec4c5ddb504ca60fc29472f3d27e8d4da1257a854e1d96742f15c1d02d/distlib-0.3.9.tar.gz", hash = "sha256:a60f20dea646b8a33f3e7772f74dc0b2d0772d2837ee1342a00645c81edf9403", size = 613923 } wheels = [ { url = "https://files.pythonhosted.org/packages/91/a1/cf2472db20f7ce4a6be1253a81cfdf85ad9c7885ffbed7047fb72c24cf87/distlib-0.3.9-py2.py3-none-any.whl", hash = "sha256:47f8c22fd27c27e25a65601af709b38e4f0a45ea4fc2e710f65755fa8caaaf87", size = 468973 }, ] [[package]] name = "docopt" version = "0.6.2" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/a2/55/8f8cab2afd404cf578136ef2cc5dfb50baa1761b68c9da1fb1e4eed343c9/docopt-0.6.2.tar.gz", hash = "sha256:49b3a825280bd66b3aa83585ef59c4a8c82f2c8a522dbe754a8bc8d08c85c491", size = 25901 } [[package]] name = "docstring-parser" version = "0.16" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/08/12/9c22a58c0b1e29271051222d8906257616da84135af9ed167c9e28f85cb3/docstring_parser-0.16.tar.gz", hash = "sha256:538beabd0af1e2db0146b6bd3caa526c35a34d61af9fd2887f3a8a27a739aa6e", size = 26565 } wheels = [ { url = "https://files.pythonhosted.org/packages/d5/7c/e9fcff7623954d86bdc17782036cbf715ecab1bec4847c008557affe1ca8/docstring_parser-0.16-py3-none-any.whl", hash = "sha256:bf0a1387354d3691d102edef7ec124f219ef639982d096e26e3b60aeffa90637", size = 36533 }, ] [[package]] name = "example-isort-sorting-plugin" version = "0.1.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "natsort" }, ] sdist = { url = "https://files.pythonhosted.org/packages/d8/4a/eef19c44d8a952b8993665fb9d67338deccab506607072d7a45c7c46d369/example_isort_sorting_plugin-0.1.0.tar.gz", hash = "sha256:cb9112a5aaa0483086b362f201bdb01a65cf711a281c0d0bcf00b2a9bb14a8e7", size = 1110 } wheels = [ { url = "https://files.pythonhosted.org/packages/9c/2d/1fda94a5ddd0c0b713ca8141a269a89592554dda86b4066ac147b4c4d9bc/example_isort_sorting_plugin-0.1.0-py3-none-any.whl", hash = "sha256:4a41342268a880c2a00aada25c8fc269efec1baa3b79207a429a0b8a68a2f071", size = 1719 }, ] [[package]] name = "example-shared-isort-profile" version = "0.1.0" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/a7/31/ff8151ccbc393c2e19b855c09a8a4dd8bbf0178b79e3ed9d93c278569ff0/example_shared_isort_profile-0.1.0.tar.gz", hash = "sha256:c40d63639a64a6c641c84648d891f29370f446f3c6afd57e61430cfa45cd3b84", size = 1022 } wheels = [ { url = "https://files.pythonhosted.org/packages/ab/cb/915806bb31b949283adc89f8af29bd736b47c7ca3e816cd11bfef40d0c9f/example_shared_isort_profile-0.1.0-py3-none-any.whl", hash = "sha256:579fb3cd8db5fd63b9b1d426090167640f695a17056e9e5f75bcd9a44341f70b", size = 1643 }, ] [[package]] name = "exceptiongroup" version = "1.2.2" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/09/35/2495c4ac46b980e4ca1f6ad6db102322ef3ad2410b79fdde159a4b0f3b92/exceptiongroup-1.2.2.tar.gz", hash = "sha256:47c2edf7c6738fafb49fd34290706d1a1a2f4d1c6df275526b62cbb4aa5393cc", size = 28883 } wheels = [ { url = "https://files.pythonhosted.org/packages/02/cc/b7e31358aac6ed1ef2bb790a9746ac2c69bcb3c8588b41616914eb106eaf/exceptiongroup-1.2.2-py3-none-any.whl", hash = "sha256:3111b9d131c238bec2f8f516e123e14ba243563fb135d3fe885990585aa7795b", size = 16453 }, ] [[package]] name = "executing" version = "2.1.0" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/8c/e3/7d45f492c2c4a0e8e0fad57d081a7c8a0286cdd86372b070cca1ec0caa1e/executing-2.1.0.tar.gz", hash = "sha256:8ea27ddd260da8150fa5a708269c4a10e76161e2496ec3e587da9e3c0fe4b9ab", size = 977485 } wheels = [ { url = "https://files.pythonhosted.org/packages/b5/fd/afcd0496feca3276f509df3dbd5dae726fcc756f1a08d9e25abe1733f962/executing-2.1.0-py2.py3-none-any.whl", hash = "sha256:8d63781349375b5ebccc3142f4b30350c0cd9c79f921cde38be2be4637e98eaf", size = 25805 }, ] [[package]] name = "falcon" version = "2.0.0" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/19/30/edff5a1fea7a8e9876c8391e170263e1bb207875b6a65cd619818487b27b/falcon-2.0.0.tar.gz", hash = "sha256:eea593cf466b9c126ce667f6d30503624ef24459f118c75594a69353b6c3d5fc", size = 397801 } wheels = [ { url = "https://files.pythonhosted.org/packages/4b/89/37b132c6ae7f85c60a1549f9e46109eec40cf0c31f0305faecb7f7bcfceb/falcon-2.0.0-py2.py3-none-any.whl", hash = "sha256:54f2cb4b687035b2a03206dbfc538055cc48b59a953187b0458aa1b574d47b53", size = 163982 }, ] [[package]] name = "fastjsonschema" version = "2.21.1" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/8b/50/4b769ce1ac4071a1ef6d86b1a3fb56cdc3a37615e8c5519e1af96cdac366/fastjsonschema-2.21.1.tar.gz", hash = "sha256:794d4f0a58f848961ba16af7b9c85a3e88cd360df008c59aac6fc5ae9323b5d4", size = 373939 } wheels = [ { url = "https://files.pythonhosted.org/packages/90/2b/0817a2b257fe88725c25589d89aec060581aabf668707a8d03b2e9e0cb2a/fastjsonschema-2.21.1-py3-none-any.whl", hash = "sha256:c9e5b7e908310918cf494a434eeb31384dd84a98b57a30bcb1f535015b554667", size = 23924 }, ] [[package]] name = "filelock" version = "3.16.1" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/9d/db/3ef5bb276dae18d6ec2124224403d1d67bccdbefc17af4cc8f553e341ab1/filelock-3.16.1.tar.gz", hash = "sha256:c249fbfcd5db47e5e2d6d62198e565475ee65e4831e2561c8e313fa7eb961435", size = 18037 } wheels = [ { url = "https://files.pythonhosted.org/packages/b9/f8/feced7779d755758a52d1f6635d990b8d98dc0a29fa568bbe0625f18fdf3/filelock-3.16.1-py3-none-any.whl", hash = "sha256:2082e5703d51fbf98ea75855d9d5527e33d8ff23099bec374a134febee6946b0", size = 16163 }, ] [[package]] name = "flake8" version = "7.0.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "mccabe" }, { name = "pycodestyle" }, { name = "pyflakes" }, ] sdist = { url = "https://files.pythonhosted.org/packages/40/3c/3464b567aa367b221fa610bbbcce8015bf953977d21e52f2d711b526fb48/flake8-7.0.0.tar.gz", hash = "sha256:33f96621059e65eec474169085dc92bf26e7b2d47366b70be2f67ab80dc25132", size = 48219 } wheels = [ { url = "https://files.pythonhosted.org/packages/e3/01/cc8cdec7b61db0315c2ab62d80677a138ef06832ec17f04d87e6ef858f7f/flake8-7.0.0-py2.py3-none-any.whl", hash = "sha256:a6dfbb75e03252917f2473ea9653f7cd799c3064e54d4c8140044c5c065f53c3", size = 57570 }, ] [[package]] name = "flake8-bugbear" version = "24.12.12" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "attrs" }, { name = "flake8" }, ] sdist = { url = "https://files.pythonhosted.org/packages/c7/25/48ba712ff589b0149f21135234f9bb45c14d6689acc6151b5e2ff8ac2ae9/flake8_bugbear-24.12.12.tar.gz", hash = "sha256:46273cef0a6b6ff48ca2d69e472f41420a42a46e24b2a8972e4f0d6733d12a64", size = 82907 } wheels = [ { url = "https://files.pythonhosted.org/packages/b9/21/0a875f75fbe4008bd171e2fefa413536258fe6b4cfaaa087986de74588f4/flake8_bugbear-24.12.12-py3-none-any.whl", hash = "sha256:1b6967436f65ca22a42e5373aaa6f2d87966ade9aa38d4baf2a1be550767545e", size = 36664 }, ] [[package]] name = "flake8-pyproject" version = "1.2.3" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "flake8" }, { name = "tomli", marker = "python_full_version < '3.11'" }, ] wheels = [ { url = "https://files.pythonhosted.org/packages/5f/1d/635e86f9f3a96b7ea9e9f19b5efe17a987e765c39ca496e4a893bb999112/flake8_pyproject-1.2.3-py3-none-any.whl", hash = "sha256:6249fe53545205af5e76837644dc80b4c10037e73a0e5db87ff562d75fb5bd4a", size = 4756 }, ] [[package]] name = "ghp-import" version = "2.1.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "python-dateutil" }, ] sdist = { url = "https://files.pythonhosted.org/packages/d9/29/d40217cbe2f6b1359e00c6c307bb3fc876ba74068cbab3dde77f03ca0dc4/ghp-import-2.1.0.tar.gz", hash = "sha256:9c535c4c61193c2df8871222567d7fd7e5014d835f97dc7b7439069e2413d343", size = 10943 } wheels = [ { url = "https://files.pythonhosted.org/packages/f7/ec/67fbef5d497f86283db54c22eec6f6140243aae73265799baaaa19cd17fb/ghp_import-2.1.0-py3-none-any.whl", hash = "sha256:8337dd7b50877f163d4c0289bc1f1c7f127550241988d568c1db512c4324a619", size = 11034 }, ] [[package]] name = "gitdb" version = "4.0.12" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "smmap" }, ] sdist = { url = "https://files.pythonhosted.org/packages/72/94/63b0fc47eb32792c7ba1fe1b694daec9a63620db1e313033d18140c2320a/gitdb-4.0.12.tar.gz", hash = "sha256:5ef71f855d191a3326fcfbc0d5da835f26b13fbcba60c32c21091c349ffdb571", size = 394684 } wheels = [ { url = "https://files.pythonhosted.org/packages/a0/61/5c78b91c3143ed5c14207f463aecfc8f9dbb5092fb2869baf37c273b2705/gitdb-4.0.12-py3-none-any.whl", hash = "sha256:67073e15955400952c6565cc3e707c554a4eea2e428946f7a4c162fab9bd9bcf", size = 62794 }, ] [[package]] name = "gitpython" version = "3.1.44" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "gitdb" }, ] sdist = { url = "https://files.pythonhosted.org/packages/c0/89/37df0b71473153574a5cdef8f242de422a0f5d26d7a9e231e6f169b4ad14/gitpython-3.1.44.tar.gz", hash = "sha256:c87e30b26253bf5418b01b0660f818967f3c503193838337fe5e573331249269", size = 214196 } wheels = [ { url = "https://files.pythonhosted.org/packages/1d/9a/4114a9057db2f1462d5c8f8390ab7383925fe1ac012eaa42402ad65c2963/GitPython-3.1.44-py3-none-any.whl", hash = "sha256:9e0e10cda9bed1ee64bc9a6de50e7e38a9c9943241cd7f585f6df3ed28011110", size = 207599 }, ] [[package]] name = "h11" version = "0.14.0" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/f5/38/3af3d3633a34a3316095b39c8e8fb4853a28a536e55d347bd8d8e9a14b03/h11-0.14.0.tar.gz", hash = "sha256:8f19fbbe99e72420ff35c00b27a34cb9937e902a8b810e2c88300c6f0a3b699d", size = 100418 } wheels = [ { url = "https://files.pythonhosted.org/packages/95/04/ff642e65ad6b90db43e668d70ffb6736436c7ce41fcc549f4e9472234127/h11-0.14.0-py3-none-any.whl", hash = "sha256:e3fe4ac4b851c468cc8363d500db52c2ead036020723024a109d37346efaa761", size = 58259 }, ] [[package]] name = "hatch" version = "1.14.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "click" }, { name = "hatchling" }, { name = "httpx" }, { name = "hyperlink" }, { name = "keyring" }, { name = "packaging" }, { name = "pexpect" }, { name = "platformdirs" }, { name = "rich" }, { name = "shellingham" }, { name = "tomli-w" }, { name = "tomlkit" }, { name = "userpath" }, { name = "uv" }, { name = "virtualenv" }, { name = "zstandard" }, ] sdist = { url = "https://files.pythonhosted.org/packages/bc/15/b4e3d50d8177e6e8a243b24d9819e3807f7bfd3b2bebe7b5aef32a9c79cb/hatch-1.14.0.tar.gz", hash = "sha256:351e41bc6c72bc93cb98651212226e495b43549eee27c487832e459e5d0f0eda", size = 5188143 } wheels = [ { url = "https://files.pythonhosted.org/packages/85/c6/ad910cdb79600af0100b7c4f7093eb4b95a2b44e589e66b6b938b09cc6f9/hatch-1.14.0-py3-none-any.whl", hash = "sha256:b12c7a2f4aaf6db7180e35c476e1a2ad4ec7197c20c4332964599424d4918ded", size = 125763 }, ] [[package]] name = "hatchling" version = "1.27.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "packaging" }, { name = "pathspec" }, { name = "pluggy" }, { name = "tomli", marker = "python_full_version < '3.11'" }, { name = "trove-classifiers" }, ] sdist = { url = "https://files.pythonhosted.org/packages/8f/8a/cc1debe3514da292094f1c3a700e4ca25442489731ef7c0814358816bb03/hatchling-1.27.0.tar.gz", hash = "sha256:971c296d9819abb3811112fc52c7a9751c8d381898f36533bb16f9791e941fd6", size = 54983 } wheels = [ { url = "https://files.pythonhosted.org/packages/08/e7/ae38d7a6dfba0533684e0b2136817d667588ae3ec984c1a4e5df5eb88482/hatchling-1.27.0-py3-none-any.whl", hash = "sha256:d3a2f3567c4f926ea39849cdf924c7e99e6686c9c8e288ae1037c8fa2a5d937b", size = 75794 }, ] [[package]] name = "httpcore" version = "1.0.7" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "certifi" }, { name = "h11" }, ] sdist = { url = "https://files.pythonhosted.org/packages/6a/41/d7d0a89eb493922c37d343b607bc1b5da7f5be7e383740b4753ad8943e90/httpcore-1.0.7.tar.gz", hash = "sha256:8551cb62a169ec7162ac7be8d4817d561f60e08eaa485234898414bb5a8a0b4c", size = 85196 } wheels = [ { url = "https://files.pythonhosted.org/packages/87/f5/72347bc88306acb359581ac4d52f23c0ef445b57157adedb9aee0cd689d2/httpcore-1.0.7-py3-none-any.whl", hash = "sha256:a3fff8f43dc260d5bd363d9f9cf1830fa3a458b332856f34282de498ed420edd", size = 78551 }, ] [[package]] name = "httpx" version = "0.28.1" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "anyio" }, { name = "certifi" }, { name = "httpcore" }, { name = "idna" }, ] sdist = { url = "https://files.pythonhosted.org/packages/b1/df/48c586a5fe32a0f01324ee087459e112ebb7224f646c0b5023f5e79e9956/httpx-0.28.1.tar.gz", hash = "sha256:75e98c5f16b0f35b567856f597f06ff2270a374470a5c2392242528e3e3e42fc", size = 141406 } wheels = [ { url = "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl", hash = "sha256:d909fcccc110f8c7faf814ca82a9a4d816bc5a6dbfea25d6591d6985b8ba59ad", size = 73517 }, ] [[package]] name = "hug" version = "2.6.1" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "falcon" }, { name = "requests" }, ] sdist = { url = "https://files.pythonhosted.org/packages/9e/b2/0549ffd2f6bdeb37e5cbee7119830e0928ca0df12c16ab8ed68078c69239/hug-2.6.1.tar.gz", hash = "sha256:b0edace2acb618873779c9ce6ecf9165db54fef95c22262f5700fcdd9febaec9", size = 76270 } wheels = [ { url = "https://files.pythonhosted.org/packages/93/01/ee254f209868b12c5327948bd193641beaad526fc34db44923c054a016fc/hug-2.6.1-py2.py3-none-any.whl", hash = "sha256:31c8fc284f81377278629a4b94cbb619ae9ce829cdc2da9564ccc66a121046b4", size = 75085 }, ] [[package]] name = "hyperlink" version = "21.0.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "idna" }, ] sdist = { url = "https://files.pythonhosted.org/packages/3a/51/1947bd81d75af87e3bb9e34593a4cf118115a8feb451ce7a69044ef1412e/hyperlink-21.0.0.tar.gz", hash = "sha256:427af957daa58bc909471c6c40f74c5450fa123dd093fc53efd2e91d2705a56b", size = 140743 } wheels = [ { url = "https://files.pythonhosted.org/packages/6e/aa/8caf6a0a3e62863cbb9dab27135660acba46903b703e224f14f447e57934/hyperlink-21.0.0-py2.py3-none-any.whl", hash = "sha256:e6b14c37ecb73e89c77d78cdb4c2cc8f3fb59a885c5b3f819ff4ed80f25af1b4", size = 74638 }, ] [[package]] name = "hypothesis" version = "6.124.1" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "attrs" }, { name = "exceptiongroup", marker = "python_full_version < '3.11'" }, { name = "sortedcontainers" }, ] sdist = { url = "https://files.pythonhosted.org/packages/df/bf/f887421cc40ef306f1c85d0ad8e6dee965010652fad57e687221221f386d/hypothesis-6.124.1.tar.gz", hash = "sha256:6e21995c3cb3198ef7e60853acce1fbaa6c16de59c2fb3158845664dfe639bd9", size = 420693 } wheels = [ { url = "https://files.pythonhosted.org/packages/cc/34/599882a0dab7615cd6cbf326e11b7ac3dc2e5ee349ef3af551e70ea07237/hypothesis-6.124.1-py3-none-any.whl", hash = "sha256:40c8be982d3a79b26d5ae11b6606189784f1654f3c750ffcb99fc5b352d5e2ba", size = 483566 }, ] [package.optional-dependencies] lark = [ { name = "lark" }, ] [[package]] name = "hypothesmith" version = "0.3.3" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "hypothesis", extra = ["lark"] }, { name = "libcst" }, ] sdist = { url = "https://files.pythonhosted.org/packages/e3/f6/1a64114dee6c46985482c35bdbc12025db59973a0225eec47ac4d306030f/hypothesmith-0.3.3.tar.gz", hash = "sha256:96c14802d6c8e85d8975264176878db54b28d2ed921fdbfedc2e6b8ce3c81716", size = 25529 } wheels = [ { url = "https://files.pythonhosted.org/packages/69/bc/78dcf42c6eaaf7d628f061f1e533a596f5bca2a53be2b714adc5d370d48e/hypothesmith-0.3.3-py3-none-any.whl", hash = "sha256:fdb0172f9de97d09450da40da7da083fdd118bcd2f88b1a2289413d2d496b1b1", size = 19247 }, ] [[package]] name = "identify" version = "2.6.6" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/82/bf/c68c46601bacd4c6fb4dd751a42b6e7087240eaabc6487f2ef7a48e0e8fc/identify-2.6.6.tar.gz", hash = "sha256:7bec12768ed44ea4761efb47806f0a41f86e7c0a5fdf5950d4648c90eca7e251", size = 99217 } wheels = [ { url = "https://files.pythonhosted.org/packages/74/a1/68a395c17eeefb04917034bd0a1bfa765e7654fa150cca473d669aa3afb5/identify-2.6.6-py2.py3-none-any.whl", hash = "sha256:cbd1810bce79f8b671ecb20f53ee0ae8e86ae84b557de31d89709dc2a48ba881", size = 99083 }, ] [[package]] name = "idna" version = "3.10" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/f1/70/7703c29685631f5a7590aa73f1f1d3fa9a380e654b86af429e0934a32f7d/idna-3.10.tar.gz", hash = "sha256:12f65c9b470abda6dc35cf8e63cc574b1c52b11df2c86030af0ac09b01b13ea9", size = 190490 } wheels = [ { url = "https://files.pythonhosted.org/packages/76/c6/c88e154df9c4e1a2a66ccf0005a88dfb2650c1dffb6f5ce603dfbd452ce3/idna-3.10-py3-none-any.whl", hash = "sha256:946d195a0d259cbba61165e88e65941f16e9b36ea6ddb97f00452bae8b1287d3", size = 70442 }, ] [[package]] name = "importlib-metadata" version = "8.6.1" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "zipp" }, ] sdist = { url = "https://files.pythonhosted.org/packages/33/08/c1395a292bb23fd03bdf572a1357c5a733d3eecbab877641ceacab23db6e/importlib_metadata-8.6.1.tar.gz", hash = "sha256:310b41d755445d74569f993ccfc22838295d9fe005425094fad953d7f15c8580", size = 55767 } wheels = [ { url = "https://files.pythonhosted.org/packages/79/9d/0fb148dc4d6fa4a7dd1d8378168d9b4cd8d4560a6fbf6f0121c5fc34eb68/importlib_metadata-8.6.1-py3-none-any.whl", hash = "sha256:02a89390c1e15fdfdc0d7c6b25cb3e62650d0494005c97d6f148bf5b9787525e", size = 26971 }, ] [[package]] name = "iniconfig" version = "2.0.0" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/d7/4b/cbd8e699e64a6f16ca3a8220661b5f83792b3017d0f79807cb8708d33913/iniconfig-2.0.0.tar.gz", hash = "sha256:2d91e135bf72d31a410b17c16da610a82cb55f6b0477d1a902134b24a455b8b3", size = 4646 } wheels = [ { url = "https://files.pythonhosted.org/packages/ef/a6/62565a6e1cf69e10f5727360368e451d4b7f58beeac6173dc9db836a5b46/iniconfig-2.0.0-py3-none-any.whl", hash = "sha256:b6a85871a79d2e3b22d2d1b94ac2824226a63c6b741c88f7ae975f18b6778374", size = 5892 }, ] [[package]] name = "ipython" version = "8.12.3" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "appnope", marker = "sys_platform == 'darwin'" }, { name = "backcall" }, { name = "colorama", marker = "sys_platform == 'win32'" }, { name = "decorator" }, { name = "jedi" }, { name = "matplotlib-inline" }, { name = "pexpect", marker = "sys_platform != 'win32'" }, { name = "pickleshare" }, { name = "prompt-toolkit" }, { name = "pygments" }, { name = "stack-data" }, { name = "traitlets" }, { name = "typing-extensions", marker = "python_full_version < '3.10'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/9e/6a/44ef299b1762f5a73841e87fae8a73a8cc8aee538d6dc8c77a5afe1fd2ce/ipython-8.12.3.tar.gz", hash = "sha256:3910c4b54543c2ad73d06579aa771041b7d5707b033bd488669b4cf544e3b363", size = 5470171 } wheels = [ { url = "https://files.pythonhosted.org/packages/8d/97/8fe103906cd81bc42d3b0175b5534a9f67dccae47d6451131cf8d0d70bb2/ipython-8.12.3-py3-none-any.whl", hash = "sha256:b0340d46a933d27c657b211a329d0be23793c36595acf9e6ef4164bc01a1804c", size = 798307 }, ] [[package]] name = "isort" source = { editable = "." } [package.optional-dependencies] colors = [ { name = "colorama" }, ] plugins = [ { name = "setuptools" }, ] [package.dev-dependencies] dev = [ { name = "bandit" }, { name = "black" }, { name = "colorama" }, { name = "coverage", extra = ["toml"] }, { name = "cruft" }, { name = "example-isort-sorting-plugin" }, { name = "example-shared-isort-profile" }, { name = "flake8" }, { name = "flake8-bugbear" }, { name = "flake8-pyproject" }, { name = "hatch" }, { name = "httpx" }, { name = "hypothesis" }, { name = "hypothesmith" }, { name = "libcst" }, { name = "mypy" }, { name = "mypy-extensions" }, { name = "pep8-naming" }, { name = "pip" }, { name = "pip-api" }, { name = "pipreqs" }, { name = "portray" }, { name = "pre-commit" }, { name = "pylama" }, { name = "pytest" }, { name = "pytest-benchmark" }, { name = "pytest-mock" }, { name = "requirementslib" }, { name = "ruff" }, { name = "stdlibs" }, { name = "toml" }, { name = "types-colorama" }, { name = "types-setuptools" }, { name = "types-toml" }, { name = "vulture" }, ] [package.metadata] requires-dist = [ { name = "colorama", marker = "extra == 'colors'" }, { name = "setuptools", marker = "extra == 'plugins'" }, ] provides-extras = ["colors", "plugins"] [package.metadata.requires-dev] dev = [ { name = "bandit", specifier = ">=1.7.7" }, { name = "black", specifier = ">=24.3.0" }, { name = "colorama", specifier = ">=0.4.6" }, { name = "coverage", extras = ["toml"], specifier = ">=6.5.0" }, { name = "cruft", specifier = ">=2.12.0" }, { name = "example-isort-sorting-plugin", specifier = ">=0.1.0" }, { name = "example-shared-isort-profile", specifier = ">=0.1.0" }, { name = "flake8", specifier = ">=3.8.4" }, { name = "flake8-bugbear", specifier = ">=22.12.12" }, { name = "flake8-pyproject", specifier = ">=1.2.3" }, { name = "hatch", specifier = ">=1.14.0" }, { name = "httpx", specifier = ">=0.13.3" }, { name = "hypothesis", specifier = ">=6.10.1" }, { name = "hypothesmith", specifier = ">=0.1.3" }, { name = "libcst", specifier = ">=0.3.18" }, { name = "mypy", specifier = ">=1.14.1" }, { name = "mypy-extensions", specifier = ">=0.4.3" }, { name = "pep8-naming", specifier = ">=0.8.2" }, { name = "pip", specifier = ">=21.1.1" }, { name = "pip-api", specifier = ">=0.0.12" }, { name = "pipreqs", specifier = ">=0.4.9" }, { name = "portray", specifier = ">=1.8.0" }, { name = "pre-commit", specifier = ">=2.13.0" }, { name = "pylama", specifier = ">=7.7" }, { name = "pytest", specifier = ">=7.4.2" }, { name = "pytest-benchmark", specifier = ">=3.4.1" }, { name = "pytest-mock", specifier = ">=1.10" }, { name = "requirementslib", specifier = ">=1.5" }, { name = "ruff", specifier = ">=0.9.6" }, { name = "stdlibs", specifier = ">=2024.10.21.16" }, { name = "toml", specifier = ">=0.10.2" }, { name = "types-colorama", specifier = ">=0.4.2" }, { name = "types-setuptools", specifier = ">=70.0.0.20240523" }, { name = "types-toml", specifier = ">=0.1.3" }, { name = "vulture", specifier = ">=1.0" }, ] [[package]] name = "jaraco-classes" version = "3.4.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "more-itertools" }, ] sdist = { url = "https://files.pythonhosted.org/packages/06/c0/ed4a27bc5571b99e3cff68f8a9fa5b56ff7df1c2251cc715a652ddd26402/jaraco.classes-3.4.0.tar.gz", hash = "sha256:47a024b51d0239c0dd8c8540c6c7f484be3b8fcf0b2d85c13825780d3b3f3acd", size = 11780 } wheels = [ { url = "https://files.pythonhosted.org/packages/7f/66/b15ce62552d84bbfcec9a4873ab79d993a1dd4edb922cbfccae192bd5b5f/jaraco.classes-3.4.0-py3-none-any.whl", hash = "sha256:f662826b6bed8cace05e7ff873ce0f9283b5c924470fe664fff1c2f00f581790", size = 6777 }, ] [[package]] name = "jaraco-context" version = "6.0.1" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "backports-tarfile", marker = "python_full_version < '3.12'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/df/ad/f3777b81bf0b6e7bc7514a1656d3e637b2e8e15fab2ce3235730b3e7a4e6/jaraco_context-6.0.1.tar.gz", hash = "sha256:9bae4ea555cf0b14938dc0aee7c9f32ed303aa20a3b73e7dc80111628792d1b3", size = 13912 } wheels = [ { url = "https://files.pythonhosted.org/packages/ff/db/0c52c4cf5e4bd9f5d7135ec7669a3a767af21b3a308e1ed3674881e52b62/jaraco.context-6.0.1-py3-none-any.whl", hash = "sha256:f797fc481b490edb305122c9181830a3a5b76d84ef6d1aef2fb9b47ab956f9e4", size = 6825 }, ] [[package]] name = "jaraco-functools" version = "4.1.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "more-itertools" }, ] sdist = { url = "https://files.pythonhosted.org/packages/ab/23/9894b3df5d0a6eb44611c36aec777823fc2e07740dabbd0b810e19594013/jaraco_functools-4.1.0.tar.gz", hash = "sha256:70f7e0e2ae076498e212562325e805204fc092d7b4c17e0e86c959e249701a9d", size = 19159 } wheels = [ { url = "https://files.pythonhosted.org/packages/9f/4f/24b319316142c44283d7540e76c7b5a6dbd5db623abd86bb7b3491c21018/jaraco.functools-4.1.0-py3-none-any.whl", hash = "sha256:ad159f13428bc4acbf5541ad6dec511f91573b90fba04df61dafa2a1231cf649", size = 10187 }, ] [[package]] name = "jedi" version = "0.19.2" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "parso" }, ] sdist = { url = "https://files.pythonhosted.org/packages/72/3a/79a912fbd4d8dd6fbb02bf69afd3bb72cf0c729bb3063c6f4498603db17a/jedi-0.19.2.tar.gz", hash = "sha256:4770dc3de41bde3966b02eb84fbcf557fb33cce26ad23da12c742fb50ecb11f0", size = 1231287 } wheels = [ { url = "https://files.pythonhosted.org/packages/c0/5a/9cac0c82afec3d09ccd97c8b6502d48f165f9124db81b4bcb90b4af974ee/jedi-0.19.2-py2.py3-none-any.whl", hash = "sha256:a8ef22bde8490f57fe5c7681a3c83cb58874daf72b4784de3cce5b6ef6edb5b9", size = 1572278 }, ] [[package]] name = "jeepney" version = "0.8.0" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/d6/f4/154cf374c2daf2020e05c3c6a03c91348d59b23c5366e968feb198306fdf/jeepney-0.8.0.tar.gz", hash = "sha256:5efe48d255973902f6badc3ce55e2aa6c5c3b3bc642059ef3a91247bcfcc5806", size = 106005 } wheels = [ { url = "https://files.pythonhosted.org/packages/ae/72/2a1e2290f1ab1e06f71f3d0f1646c9e4634e70e1d37491535e19266e8dc9/jeepney-0.8.0-py3-none-any.whl", hash = "sha256:c0a454ad016ca575060802ee4d590dd912e35c122fa04e70306de3d076cce755", size = 48435 }, ] [[package]] name = "jinja2" version = "3.1.5" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "markupsafe" }, ] sdist = { url = "https://files.pythonhosted.org/packages/af/92/b3130cbbf5591acf9ade8708c365f3238046ac7cb8ccba6e81abccb0ccff/jinja2-3.1.5.tar.gz", hash = "sha256:8fefff8dc3034e27bb80d67c671eb8a9bc424c0ef4c0826edbff304cceff43bb", size = 244674 } wheels = [ { url = "https://files.pythonhosted.org/packages/bd/0f/2ba5fbcd631e3e88689309dbe978c5769e883e4b84ebfe7da30b43275c5a/jinja2-3.1.5-py3-none-any.whl", hash = "sha256:aba0f4dc9ed8013c424088f68a5c226f7d6097ed89b246d7749c2ec4175c6adb", size = 134596 }, ] [[package]] name = "jsonschema" version = "4.23.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "attrs" }, { name = "jsonschema-specifications" }, { name = "referencing" }, { name = "rpds-py" }, ] sdist = { url = "https://files.pythonhosted.org/packages/38/2e/03362ee4034a4c917f697890ccd4aec0800ccf9ded7f511971c75451deec/jsonschema-4.23.0.tar.gz", hash = "sha256:d71497fef26351a33265337fa77ffeb82423f3ea21283cd9467bb03999266bc4", size = 325778 } wheels = [ { url = "https://files.pythonhosted.org/packages/69/4a/4f9dbeb84e8850557c02365a0eee0649abe5eb1d84af92a25731c6c0f922/jsonschema-4.23.0-py3-none-any.whl", hash = "sha256:fbadb6f8b144a8f8cf9f0b89ba94501d143e50411a1278633f56a7acf7fd5566", size = 88462 }, ] [[package]] name = "jsonschema-specifications" version = "2024.10.1" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "referencing" }, ] sdist = { url = "https://files.pythonhosted.org/packages/10/db/58f950c996c793472e336ff3655b13fbcf1e3b359dcf52dcf3ed3b52c352/jsonschema_specifications-2024.10.1.tar.gz", hash = "sha256:0f38b83639958ce1152d02a7f062902c41c8fd20d558b0c34344292d417ae272", size = 15561 } wheels = [ { url = "https://files.pythonhosted.org/packages/d1/0f/8910b19ac0670a0f80ce1008e5e751c4a57e14d2c4c13a482aa6079fa9d6/jsonschema_specifications-2024.10.1-py3-none-any.whl", hash = "sha256:a09a0680616357d9a0ecf05c12ad234479f549239d0f5b55f3deea67475da9bf", size = 18459 }, ] [[package]] name = "jupyter-client" version = "8.6.3" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "importlib-metadata", marker = "python_full_version < '3.10'" }, { name = "jupyter-core" }, { name = "python-dateutil" }, { name = "pyzmq" }, { name = "tornado" }, { name = "traitlets" }, ] sdist = { url = "https://files.pythonhosted.org/packages/71/22/bf9f12fdaeae18019a468b68952a60fe6dbab5d67cd2a103cac7659b41ca/jupyter_client-8.6.3.tar.gz", hash = "sha256:35b3a0947c4a6e9d589eb97d7d4cd5e90f910ee73101611f01283732bd6d9419", size = 342019 } wheels = [ { url = "https://files.pythonhosted.org/packages/11/85/b0394e0b6fcccd2c1eeefc230978a6f8cb0c5df1e4cd3e7625735a0d7d1e/jupyter_client-8.6.3-py3-none-any.whl", hash = "sha256:e8a19cc986cc45905ac3362915f410f3af85424b4c0905e94fa5f2cb08e8f23f", size = 106105 }, ] [[package]] name = "jupyter-core" version = "5.7.2" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "platformdirs" }, { name = "pywin32", marker = "platform_python_implementation != 'PyPy' and sys_platform == 'win32'" }, { name = "traitlets" }, ] sdist = { url = "https://files.pythonhosted.org/packages/00/11/b56381fa6c3f4cc5d2cf54a7dbf98ad9aa0b339ef7a601d6053538b079a7/jupyter_core-5.7.2.tar.gz", hash = "sha256:aa5f8d32bbf6b431ac830496da7392035d6f61b4f54872f15c4bd2a9c3f536d9", size = 87629 } wheels = [ { url = "https://files.pythonhosted.org/packages/c9/fb/108ecd1fe961941959ad0ee4e12ee7b8b1477247f30b1fdfd83ceaf017f0/jupyter_core-5.7.2-py3-none-any.whl", hash = "sha256:4f7315d2f6b4bcf2e3e7cb6e46772eba760ae459cd1f59d29eb57b0a01bd7409", size = 28965 }, ] [[package]] name = "jupyterlab-pygments" version = "0.3.0" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/90/51/9187be60d989df97f5f0aba133fa54e7300f17616e065d1ada7d7646b6d6/jupyterlab_pygments-0.3.0.tar.gz", hash = "sha256:721aca4d9029252b11cfa9d185e5b5af4d54772bb8072f9b7036f4170054d35d", size = 512900 } wheels = [ { url = "https://files.pythonhosted.org/packages/b1/dd/ead9d8ea85bf202d90cc513b533f9c363121c7792674f78e0d8a854b63b4/jupyterlab_pygments-0.3.0-py3-none-any.whl", hash = "sha256:841a89020971da1d8693f1a99997aefc5dc424bb1b251fd6322462a1b8842780", size = 15884 }, ] [[package]] name = "keyring" version = "25.6.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "importlib-metadata", marker = "python_full_version < '3.12'" }, { name = "jaraco-classes" }, { name = "jaraco-context" }, { name = "jaraco-functools" }, { name = "jeepney", marker = "sys_platform == 'linux'" }, { name = "pywin32-ctypes", marker = "sys_platform == 'win32'" }, { name = "secretstorage", marker = "sys_platform == 'linux'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/70/09/d904a6e96f76ff214be59e7aa6ef7190008f52a0ab6689760a98de0bf37d/keyring-25.6.0.tar.gz", hash = "sha256:0b39998aa941431eb3d9b0d4b2460bc773b9df6fed7621c2dfb291a7e0187a66", size = 62750 } wheels = [ { url = "https://files.pythonhosted.org/packages/d3/32/da7f44bcb1105d3e88a0b74ebdca50c59121d2ddf71c9e34ba47df7f3a56/keyring-25.6.0-py3-none-any.whl", hash = "sha256:552a3f7af126ece7ed5c89753650eec89c7eaae8617d0aa4d9ad2b75111266bd", size = 39085 }, ] [[package]] name = "lark" version = "1.2.2" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/af/60/bc7622aefb2aee1c0b4ba23c1446d3e30225c8770b38d7aedbfb65ca9d5a/lark-1.2.2.tar.gz", hash = "sha256:ca807d0162cd16cef15a8feecb862d7319e7a09bdb13aef927968e45040fed80", size = 252132 } wheels = [ { url = "https://files.pythonhosted.org/packages/2d/00/d90b10b962b4277f5e64a78b6609968859ff86889f5b898c1a778c06ec00/lark-1.2.2-py3-none-any.whl", hash = "sha256:c2276486b02f0f1b90be155f2c8ba4a8e194d42775786db622faccd652d8e80c", size = 111036 }, ] [[package]] name = "libcst" version = "1.6.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "pyyaml" }, ] sdist = { url = "https://files.pythonhosted.org/packages/f4/ec/d24c0ad33838dfbfe20a760b301d529c63cef32f8b91dae380c97f8bf127/libcst-1.6.0.tar.gz", hash = "sha256:e80ecdbe3fa43b3793cae8fa0b07a985bd9a693edbe6e9d076f5422ecadbf0db", size = 776146 } wheels = [ { url = "https://files.pythonhosted.org/packages/06/10/2d14576a0ddf14c08c4b92276abd04c0220c3b9fb006f6d5b6f91d403082/libcst-1.6.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:2f02d0da6dfbad44e6ec4d1e5791e17afe95d9fe89bce4374bf109fd9c103a50", size = 2049474 }, { url = "https://files.pythonhosted.org/packages/39/39/04893c1555dd59e4c6e25cd7a6afa6162ccd088a669ed106d992c7b3baca/libcst-1.6.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:48406225378ee9208edb1e5a10451bea810262473af1a2f2473737fd16d34e3a", size = 2206659 }, { url = "https://files.pythonhosted.org/packages/87/f1/584a83f9b8b0ff18ec79b4daca6bb459abe63b854a67e11d17948b0b0d7f/libcst-1.6.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8bf59a21e9968dc4e7c301fac660bf54bc7d4dcadc0b1abf31b1cac34e800555", size = 2311551 }, { url = "https://files.pythonhosted.org/packages/d8/8e/24772a6d7f94b68b1bfbfb767870558a4ecc7d2c728f9dba5c044bc6130b/libcst-1.6.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d65550ac686bff9395398afacbc88fe812363703a4161108e8a6db066d30b96e", size = 2394319 }, { url = "https://files.pythonhosted.org/packages/d5/84/be29a71cd2c5f4079fa05675b140ec2a83f7b425ee8f75f17232f6223cc7/libcst-1.6.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:5ac6d68364031f0b554d8920a69b33f25ec6ef351fa31b4e8f3676abb729ce36", size = 2254468 }, { url = "https://files.pythonhosted.org/packages/a7/16/85d97cd594ca9d38d4f7ea71e13eb43a362374de8b436119f09c95999477/libcst-1.6.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:0c0fb2f7b74605832cc38d79e9d104f92a8aaeec7bf8f2759b20c5ba3786a321", size = 2372379 }, { url = "https://files.pythonhosted.org/packages/de/87/53bea5e4e783ddf2b785c4706fdfc5fd74561a47f99995cc1d9f300d20f1/libcst-1.6.0-cp310-cp310-win_amd64.whl", hash = "sha256:1bd11863889b630fe41543b4eb5e2dd445447a7f89e6b58229e83c9e52a74942", size = 2076554 }, { url = "https://files.pythonhosted.org/packages/9e/d6/d6b2b6a997cdec90f2492954a1868de7df90d2d7a0b9267e14ded5713c91/libcst-1.6.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:a9e71a046b4a91950125967f5ee67389f25a2511103e5595508f0591a5f50bc0", size = 2049175 }, { url = "https://files.pythonhosted.org/packages/18/26/cc5852f725042dff5df2ca98d362f0c633bd70ee14e252665293c7f9b67d/libcst-1.6.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:df3f452e074893dfad7746a041caeb3cde75bd9fbca4ea7b223012e112d1da8c", size = 2206182 }, { url = "https://files.pythonhosted.org/packages/a2/fe/4227e6c34a96b1fe36bbe0f48ebe09cbed267a89ab4827bed58a794776ee/libcst-1.6.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:31e45f88d4a9a8e5b690ed14a564fcbace14b10f5e7b6797d6d97f4226b395da", size = 2311286 }, { url = "https://files.pythonhosted.org/packages/22/c1/db676774b3e3e6d7e604d4b520df609c8c9e7990c39c3c2a2216687c1d6c/libcst-1.6.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1bd00399d20bf93590b6f02647f8be08e2b730e050e6b7360f669254e69c98f5", size = 2393885 }, { url = "https://files.pythonhosted.org/packages/6b/8a/5cb362e992d3ad822ea93233175e0f26da16bf852532969918da439a85a5/libcst-1.6.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:d25132f24edc24895082589645dbb8972c0eff6c9716ff71932fa72643d7c74f", size = 2254001 }, { url = "https://files.pythonhosted.org/packages/a9/65/81bd981ca6e1712b16ec1c43b90e886cacb36bd6e12f50c27550ade4dc1a/libcst-1.6.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:38f3f25d4f5d8713cdb6a7bd41d75299de3c2416b9890a34d9b05417b8e64c1d", size = 2371855 }, { url = "https://files.pythonhosted.org/packages/d4/87/f1613e0ec216f29fd45e720eef1e440adfefc809d4e1bb3fc466a1db49bc/libcst-1.6.0-cp311-cp311-win_amd64.whl", hash = "sha256:91242ccbae6e7a070b33ebe03d3677c54bf678653538fbaa89597a59e4a13b2d", size = 2076392 }, { url = "https://files.pythonhosted.org/packages/89/ca/4b92261d0cecfab5e22ccd7582f5b2d6fec9ec19884d28d66f1bc1dc9b79/libcst-1.6.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:cd2b28688dabf0f7a166b47ab1c7d5c0b6ef8c9a05ad932618471a33fe591a4a", size = 2044342 }, { url = "https://files.pythonhosted.org/packages/39/cb/3764a5eb00e3e31f3ce28e8abd1aa99934bc63006798799593d3525d2677/libcst-1.6.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6a12a4766ce5874ccb31a1cc095cff47e2fb35755954965fe77458d9e5b361a8", size = 2202123 }, { url = "https://files.pythonhosted.org/packages/6e/0d/ec24969e39a6d9afee6080366de7303d59b43611882a29b30fc28dba0488/libcst-1.6.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bfcd78a5e775f155054ed50d047a260cd23f0f6a89ef2a57e10bdb9c697680b8", size = 2303775 }, { url = "https://files.pythonhosted.org/packages/36/a3/c40304fe76c3add626dc19ab2c1ecbcfd1df7714414d7b4e3a0d130a8389/libcst-1.6.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5786240358b122ad901bb0b7e6b7467085b2317333233d7c7d7cac46388fbd77", size = 2388341 }, { url = "https://files.pythonhosted.org/packages/c3/f1/e820b8f9e19769ca7a57a719980abacf805609777a58df68ed1cb8cd328d/libcst-1.6.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:c527472093b5b64ffa65d33c472da38952827abbca18c786d559d6d6122bc891", size = 2248883 }, { url = "https://files.pythonhosted.org/packages/6c/d4/bc4c91f61dbb892db53148f39d6d8a45a5cbb4c19953ededb39bbcf60d3d/libcst-1.6.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:63a8893dfc344b9b08bfaf4e433b16a7e2e9361f8362fa73eaecc4d379c328ba", size = 2365027 }, { url = "https://files.pythonhosted.org/packages/e1/b5/d84b56528f88e7f3fe792b91bd21beb406159b3283bd7c891737982f7b07/libcst-1.6.0-cp312-cp312-win_amd64.whl", hash = "sha256:4cd011fcd79b76be216440ec296057780223674bc2566662c4bc50d3c5ecd58e", size = 2070680 }, { url = "https://files.pythonhosted.org/packages/04/3e/80f5bbcc06a8d101d1a35ff1c7c0866e6b41ae07843a47e5c6c84f5bbf10/libcst-1.6.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:96506807dc01c9efcea8ab57d9ea18fdc87b85514cc8ee2f8568fab6df861f02", size = 2044340 }, { url = "https://files.pythonhosted.org/packages/2c/b3/1f36c271a91eef880740a7826d7a953dbcec434adcbee070a2e75cfb94d0/libcst-1.6.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dac722aade8796a1e78662c3ed424f0ab9f1dc0e8fdf3088610354cdd709e53f", size = 2202286 }, { url = "https://files.pythonhosted.org/packages/c4/23/dbb2bbe21c1943dcd52be7423ddb9e9b7ab1cf4c44e25cceee30fa2136db/libcst-1.6.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1b8370d0f7092a17b7fcda0e1539d0162cf35a0c19af94842b09c9dddc382acd", size = 2303867 }, { url = "https://files.pythonhosted.org/packages/e6/49/61bb0baa61745dc7b91fdb97fbed16149b22d88f254696d54645fea9df25/libcst-1.6.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8e4fcd791cab0fe8287b6edd0d78512b6475b87d906562a5d2d0999cb6d23b8d", size = 2389158 }, { url = "https://files.pythonhosted.org/packages/3c/39/dcfe6c02e087e3241e8e799b2ddb92e32a65076eec846205e96e3a928139/libcst-1.6.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:3fb953fc0155532f366ff40f6a23f191250134d6928e02074ae4eb3531fa6c30", size = 2248820 }, { url = "https://files.pythonhosted.org/packages/20/5b/db239fcf1417bdff283ed76b027b4039e1c377d38aa3b979f32bcf34fa94/libcst-1.6.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:2f3c85602e5a6d3aec0a8fc74230363f943004d7c2b2a6a1c09b320b61692241", size = 2365139 }, { url = "https://files.pythonhosted.org/packages/38/7f/ed56f5724305c08235d1edc580275aa13c8303e93d374d4fe73162907e88/libcst-1.6.0-cp313-cp313-win_amd64.whl", hash = "sha256:c4486921bebd33d67bbbd605aff8bfaefd2d13dc73c20c1fde2fb245880b7fd6", size = 2070695 }, { url = "https://files.pythonhosted.org/packages/0f/66/20afe2de02a30d74b2a3e0aacb5938a926664db73c42e430948915d02e81/libcst-1.6.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:b3d274115d134a550fe8a0b38780a28a659d4a35ac6068c7c92fffe6661b519c", size = 2049393 }, { url = "https://files.pythonhosted.org/packages/14/32/54e9f017d0824711f4a8e5f990f17ba0ff10e5763de5ecf673b590a27e28/libcst-1.6.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d45513f6cd3dbb2a80cf21a53bc6e6e560414edea17c474c784100e10aebe921", size = 2207738 }, { url = "https://files.pythonhosted.org/packages/25/29/87aa47fc8e8b233ee831629444b792161cc29934b75f1232f523f785e1c2/libcst-1.6.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f8c70a124d7a7d326abdc9a6261013c57d36f21c6c6370de5dd3e6a040c4ee5e", size = 2311951 }, { url = "https://files.pythonhosted.org/packages/27/9d/b5879b34b739fcc9826dec90686fa28aade096edd5b729cb518d31371509/libcst-1.6.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:bdc95df61838d708adb37e18af1615491f6cac59557fd11077664dd956fe4528", size = 2394329 }, { url = "https://files.pythonhosted.org/packages/ee/16/f404cdbcb4748a2184a83be33987a98c382e1f95f927b3305cc23f04a89d/libcst-1.6.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:05c32de72553cb93ff606c7d2421ce1eab1f0740c8c4b715444e2ae42f42b1b6", size = 2254964 }, { url = "https://files.pythonhosted.org/packages/9b/51/674b34974cd1c5484b29c72cf472d74f6c01b5228b231a1d97121c9fe573/libcst-1.6.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:69b705f5b1faa66f115ede52a970d7613d3a8fb988834f853f7fb46870a041d2", size = 2372717 }, { url = "https://files.pythonhosted.org/packages/85/b4/f230eddb5afdd37e96d4de6e5314cdd38b2d8ece145b7a4a523851ab21a3/libcst-1.6.0-cp39-cp39-win_amd64.whl", hash = "sha256:984512829a80f963bfc1803342219a4264a8d4206df0a30eae9bce921357a938", size = 2076934 }, ] [[package]] name = "livereload" version = "2.7.1" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "tornado" }, ] sdist = { url = "https://files.pythonhosted.org/packages/43/6e/f2748665839812a9bbe5c75d3f983edbf3ab05fa5cd2f7c2f36fffdf65bd/livereload-2.7.1.tar.gz", hash = "sha256:3d9bf7c05673df06e32bea23b494b8d36ca6d10f7d5c3c8a6989608c09c986a9", size = 22255 } wheels = [ { url = "https://files.pythonhosted.org/packages/e4/3e/de54dc7f199e85e6ca37e2e5dae2ec3bce2151e9e28f8eb9076d71e83d56/livereload-2.7.1-py3-none-any.whl", hash = "sha256:5201740078c1b9433f4b2ba22cd2729a39b9d0ec0a2cc6b4d3df257df5ad0564", size = 22657 }, ] [[package]] name = "mako" version = "1.3.8" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "markupsafe" }, ] sdist = { url = "https://files.pythonhosted.org/packages/5f/d9/8518279534ed7dace1795d5a47e49d5299dd0994eed1053996402a8902f9/mako-1.3.8.tar.gz", hash = "sha256:577b97e414580d3e088d47c2dbbe9594aa7a5146ed2875d4dfa9075af2dd3cc8", size = 392069 } wheels = [ { url = "https://files.pythonhosted.org/packages/1e/bf/7a6a36ce2e4cafdfb202752be68850e22607fccd692847c45c1ae3c17ba6/Mako-1.3.8-py3-none-any.whl", hash = "sha256:42f48953c7eb91332040ff567eb7eea69b22e7a4affbc5ba8e845e8f730f6627", size = 78569 }, ] [[package]] name = "markdown" version = "3.3.7" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "importlib-metadata", marker = "python_full_version < '3.10'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/d6/58/79df20de6e67a83f0d0bbfe6c19bb82adf68cdf362885257eb01099f930a/Markdown-3.3.7.tar.gz", hash = "sha256:cbb516f16218e643d8e0a95b309f77eb118cb138d39a4f27851e6a63581db874", size = 324130 } wheels = [ { url = "https://files.pythonhosted.org/packages/f3/df/ca72f352e15b6f8ce32b74af029f1189abffb906f7c137501ffe69c98a65/Markdown-3.3.7-py3-none-any.whl", hash = "sha256:f5da449a6e1c989a4cea2631aa8ee67caa5a2ef855d551c88f9e309f4634c621", size = 97778 }, ] [[package]] name = "markdown-it-py" version = "3.0.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "mdurl" }, ] sdist = { url = "https://files.pythonhosted.org/packages/38/71/3b932df36c1a044d397a1f92d1cf91ee0a503d91e470cbd670aa66b07ed0/markdown-it-py-3.0.0.tar.gz", hash = "sha256:e3f60a94fa066dc52ec76661e37c851cb232d92f9886b15cb560aaada2df8feb", size = 74596 } wheels = [ { url = "https://files.pythonhosted.org/packages/42/d7/1ec15b46af6af88f19b8e5ffea08fa375d433c998b8a7639e76935c14f1f/markdown_it_py-3.0.0-py3-none-any.whl", hash = "sha256:355216845c60bd96232cd8d8c40e8f9765cc86f46880e43a8fd22dc1a1a8cab1", size = 87528 }, ] [[package]] name = "markupsafe" version = "3.0.2" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/b2/97/5d42485e71dfc078108a86d6de8fa46db44a1a9295e89c5d6d4a06e23a62/markupsafe-3.0.2.tar.gz", hash = "sha256:ee55d3edf80167e48ea11a923c7386f4669df67d7994554387f84e7d8b0a2bf0", size = 20537 } wheels = [ { url = "https://files.pythonhosted.org/packages/04/90/d08277ce111dd22f77149fd1a5d4653eeb3b3eaacbdfcbae5afb2600eebd/MarkupSafe-3.0.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:7e94c425039cde14257288fd61dcfb01963e658efbc0ff54f5306b06054700f8", size = 14357 }, { url = "https://files.pythonhosted.org/packages/04/e1/6e2194baeae0bca1fae6629dc0cbbb968d4d941469cbab11a3872edff374/MarkupSafe-3.0.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9e2d922824181480953426608b81967de705c3cef4d1af983af849d7bd619158", size = 12393 }, { url = "https://files.pythonhosted.org/packages/1d/69/35fa85a8ece0a437493dc61ce0bb6d459dcba482c34197e3efc829aa357f/MarkupSafe-3.0.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:38a9ef736c01fccdd6600705b09dc574584b89bea478200c5fbf112a6b0d5579", size = 21732 }, { url = "https://files.pythonhosted.org/packages/22/35/137da042dfb4720b638d2937c38a9c2df83fe32d20e8c8f3185dbfef05f7/MarkupSafe-3.0.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bbcb445fa71794da8f178f0f6d66789a28d7319071af7a496d4d507ed566270d", size = 20866 }, { url = "https://files.pythonhosted.org/packages/29/28/6d029a903727a1b62edb51863232152fd335d602def598dade38996887f0/MarkupSafe-3.0.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:57cb5a3cf367aeb1d316576250f65edec5bb3be939e9247ae594b4bcbc317dfb", size = 20964 }, { url = "https://files.pythonhosted.org/packages/cc/cd/07438f95f83e8bc028279909d9c9bd39e24149b0d60053a97b2bc4f8aa51/MarkupSafe-3.0.2-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:3809ede931876f5b2ec92eef964286840ed3540dadf803dd570c3b7e13141a3b", size = 21977 }, { url = "https://files.pythonhosted.org/packages/29/01/84b57395b4cc062f9c4c55ce0df7d3108ca32397299d9df00fedd9117d3d/MarkupSafe-3.0.2-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:e07c3764494e3776c602c1e78e298937c3315ccc9043ead7e685b7f2b8d47b3c", size = 21366 }, { url = "https://files.pythonhosted.org/packages/bd/6e/61ebf08d8940553afff20d1fb1ba7294b6f8d279df9fd0c0db911b4bbcfd/MarkupSafe-3.0.2-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:b424c77b206d63d500bcb69fa55ed8d0e6a3774056bdc4839fc9298a7edca171", size = 21091 }, { url = "https://files.pythonhosted.org/packages/11/23/ffbf53694e8c94ebd1e7e491de185124277964344733c45481f32ede2499/MarkupSafe-3.0.2-cp310-cp310-win32.whl", hash = "sha256:fcabf5ff6eea076f859677f5f0b6b5c1a51e70a376b0579e0eadef8db48c6b50", size = 15065 }, { url = "https://files.pythonhosted.org/packages/44/06/e7175d06dd6e9172d4a69a72592cb3f7a996a9c396eee29082826449bbc3/MarkupSafe-3.0.2-cp310-cp310-win_amd64.whl", hash = "sha256:6af100e168aa82a50e186c82875a5893c5597a0c1ccdb0d8b40240b1f28b969a", size = 15514 }, { url = "https://files.pythonhosted.org/packages/6b/28/bbf83e3f76936960b850435576dd5e67034e200469571be53f69174a2dfd/MarkupSafe-3.0.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:9025b4018f3a1314059769c7bf15441064b2207cb3f065e6ea1e7359cb46db9d", size = 14353 }, { url = "https://files.pythonhosted.org/packages/6c/30/316d194b093cde57d448a4c3209f22e3046c5bb2fb0820b118292b334be7/MarkupSafe-3.0.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:93335ca3812df2f366e80509ae119189886b0f3c2b81325d39efdb84a1e2ae93", size = 12392 }, { url = "https://files.pythonhosted.org/packages/f2/96/9cdafba8445d3a53cae530aaf83c38ec64c4d5427d975c974084af5bc5d2/MarkupSafe-3.0.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2cb8438c3cbb25e220c2ab33bb226559e7afb3baec11c4f218ffa7308603c832", size = 23984 }, { url = "https://files.pythonhosted.org/packages/f1/a4/aefb044a2cd8d7334c8a47d3fb2c9f328ac48cb349468cc31c20b539305f/MarkupSafe-3.0.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a123e330ef0853c6e822384873bef7507557d8e4a082961e1defa947aa59ba84", size = 23120 }, { url = "https://files.pythonhosted.org/packages/8d/21/5e4851379f88f3fad1de30361db501300d4f07bcad047d3cb0449fc51f8c/MarkupSafe-3.0.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1e084f686b92e5b83186b07e8a17fc09e38fff551f3602b249881fec658d3eca", size = 23032 }, { url = "https://files.pythonhosted.org/packages/00/7b/e92c64e079b2d0d7ddf69899c98842f3f9a60a1ae72657c89ce2655c999d/MarkupSafe-3.0.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:d8213e09c917a951de9d09ecee036d5c7d36cb6cb7dbaece4c71a60d79fb9798", size = 24057 }, { url = "https://files.pythonhosted.org/packages/f9/ac/46f960ca323037caa0a10662ef97d0a4728e890334fc156b9f9e52bcc4ca/MarkupSafe-3.0.2-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:5b02fb34468b6aaa40dfc198d813a641e3a63b98c2b05a16b9f80b7ec314185e", size = 23359 }, { url = "https://files.pythonhosted.org/packages/69/84/83439e16197337b8b14b6a5b9c2105fff81d42c2a7c5b58ac7b62ee2c3b1/MarkupSafe-3.0.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:0bff5e0ae4ef2e1ae4fdf2dfd5b76c75e5c2fa4132d05fc1b0dabcd20c7e28c4", size = 23306 }, { url = "https://files.pythonhosted.org/packages/9a/34/a15aa69f01e2181ed8d2b685c0d2f6655d5cca2c4db0ddea775e631918cd/MarkupSafe-3.0.2-cp311-cp311-win32.whl", hash = "sha256:6c89876f41da747c8d3677a2b540fb32ef5715f97b66eeb0c6b66f5e3ef6f59d", size = 15094 }, { url = "https://files.pythonhosted.org/packages/da/b8/3a3bd761922d416f3dc5d00bfbed11f66b1ab89a0c2b6e887240a30b0f6b/MarkupSafe-3.0.2-cp311-cp311-win_amd64.whl", hash = "sha256:70a87b411535ccad5ef2f1df5136506a10775d267e197e4cf531ced10537bd6b", size = 15521 }, { url = "https://files.pythonhosted.org/packages/22/09/d1f21434c97fc42f09d290cbb6350d44eb12f09cc62c9476effdb33a18aa/MarkupSafe-3.0.2-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:9778bd8ab0a994ebf6f84c2b949e65736d5575320a17ae8984a77fab08db94cf", size = 14274 }, { url = "https://files.pythonhosted.org/packages/6b/b0/18f76bba336fa5aecf79d45dcd6c806c280ec44538b3c13671d49099fdd0/MarkupSafe-3.0.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:846ade7b71e3536c4e56b386c2a47adf5741d2d8b94ec9dc3e92e5e1ee1e2225", size = 12348 }, { url = "https://files.pythonhosted.org/packages/e0/25/dd5c0f6ac1311e9b40f4af06c78efde0f3b5cbf02502f8ef9501294c425b/MarkupSafe-3.0.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1c99d261bd2d5f6b59325c92c73df481e05e57f19837bdca8413b9eac4bd8028", size = 24149 }, { url = "https://files.pythonhosted.org/packages/f3/f0/89e7aadfb3749d0f52234a0c8c7867877876e0a20b60e2188e9850794c17/MarkupSafe-3.0.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e17c96c14e19278594aa4841ec148115f9c7615a47382ecb6b82bd8fea3ab0c8", size = 23118 }, { url = "https://files.pythonhosted.org/packages/d5/da/f2eeb64c723f5e3777bc081da884b414671982008c47dcc1873d81f625b6/MarkupSafe-3.0.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:88416bd1e65dcea10bc7569faacb2c20ce071dd1f87539ca2ab364bf6231393c", size = 22993 }, { url = "https://files.pythonhosted.org/packages/da/0e/1f32af846df486dce7c227fe0f2398dc7e2e51d4a370508281f3c1c5cddc/MarkupSafe-3.0.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:2181e67807fc2fa785d0592dc2d6206c019b9502410671cc905d132a92866557", size = 24178 }, { url = "https://files.pythonhosted.org/packages/c4/f6/bb3ca0532de8086cbff5f06d137064c8410d10779c4c127e0e47d17c0b71/MarkupSafe-3.0.2-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:52305740fe773d09cffb16f8ed0427942901f00adedac82ec8b67752f58a1b22", size = 23319 }, { url = "https://files.pythonhosted.org/packages/a2/82/8be4c96ffee03c5b4a034e60a31294daf481e12c7c43ab8e34a1453ee48b/MarkupSafe-3.0.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:ad10d3ded218f1039f11a75f8091880239651b52e9bb592ca27de44eed242a48", size = 23352 }, { url = "https://files.pythonhosted.org/packages/51/ae/97827349d3fcffee7e184bdf7f41cd6b88d9919c80f0263ba7acd1bbcb18/MarkupSafe-3.0.2-cp312-cp312-win32.whl", hash = "sha256:0f4ca02bea9a23221c0182836703cbf8930c5e9454bacce27e767509fa286a30", size = 15097 }, { url = "https://files.pythonhosted.org/packages/c1/80/a61f99dc3a936413c3ee4e1eecac96c0da5ed07ad56fd975f1a9da5bc630/MarkupSafe-3.0.2-cp312-cp312-win_amd64.whl", hash = "sha256:8e06879fc22a25ca47312fbe7c8264eb0b662f6db27cb2d3bbbc74b1df4b9b87", size = 15601 }, { url = "https://files.pythonhosted.org/packages/83/0e/67eb10a7ecc77a0c2bbe2b0235765b98d164d81600746914bebada795e97/MarkupSafe-3.0.2-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:ba9527cdd4c926ed0760bc301f6728ef34d841f405abf9d4f959c478421e4efd", size = 14274 }, { url = "https://files.pythonhosted.org/packages/2b/6d/9409f3684d3335375d04e5f05744dfe7e9f120062c9857df4ab490a1031a/MarkupSafe-3.0.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:f8b3d067f2e40fe93e1ccdd6b2e1d16c43140e76f02fb1319a05cf2b79d99430", size = 12352 }, { url = "https://files.pythonhosted.org/packages/d2/f5/6eadfcd3885ea85fe2a7c128315cc1bb7241e1987443d78c8fe712d03091/MarkupSafe-3.0.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:569511d3b58c8791ab4c2e1285575265991e6d8f8700c7be0e88f86cb0672094", size = 24122 }, { url = "https://files.pythonhosted.org/packages/0c/91/96cf928db8236f1bfab6ce15ad070dfdd02ed88261c2afafd4b43575e9e9/MarkupSafe-3.0.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:15ab75ef81add55874e7ab7055e9c397312385bd9ced94920f2802310c930396", size = 23085 }, { url = "https://files.pythonhosted.org/packages/c2/cf/c9d56af24d56ea04daae7ac0940232d31d5a8354f2b457c6d856b2057d69/MarkupSafe-3.0.2-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f3818cb119498c0678015754eba762e0d61e5b52d34c8b13d770f0719f7b1d79", size = 22978 }, { url = "https://files.pythonhosted.org/packages/2a/9f/8619835cd6a711d6272d62abb78c033bda638fdc54c4e7f4272cf1c0962b/MarkupSafe-3.0.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:cdb82a876c47801bb54a690c5ae105a46b392ac6099881cdfb9f6e95e4014c6a", size = 24208 }, { url = "https://files.pythonhosted.org/packages/f9/bf/176950a1792b2cd2102b8ffeb5133e1ed984547b75db47c25a67d3359f77/MarkupSafe-3.0.2-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:cabc348d87e913db6ab4aa100f01b08f481097838bdddf7c7a84b7575b7309ca", size = 23357 }, { url = "https://files.pythonhosted.org/packages/ce/4f/9a02c1d335caabe5c4efb90e1b6e8ee944aa245c1aaaab8e8a618987d816/MarkupSafe-3.0.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:444dcda765c8a838eaae23112db52f1efaf750daddb2d9ca300bcae1039adc5c", size = 23344 }, { url = "https://files.pythonhosted.org/packages/ee/55/c271b57db36f748f0e04a759ace9f8f759ccf22b4960c270c78a394f58be/MarkupSafe-3.0.2-cp313-cp313-win32.whl", hash = "sha256:bcf3e58998965654fdaff38e58584d8937aa3096ab5354d493c77d1fdd66d7a1", size = 15101 }, { url = "https://files.pythonhosted.org/packages/29/88/07df22d2dd4df40aba9f3e402e6dc1b8ee86297dddbad4872bd5e7b0094f/MarkupSafe-3.0.2-cp313-cp313-win_amd64.whl", hash = "sha256:e6a2a455bd412959b57a172ce6328d2dd1f01cb2135efda2e4576e8a23fa3b0f", size = 15603 }, { url = "https://files.pythonhosted.org/packages/62/6a/8b89d24db2d32d433dffcd6a8779159da109842434f1dd2f6e71f32f738c/MarkupSafe-3.0.2-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:b5a6b3ada725cea8a5e634536b1b01c30bcdcd7f9c6fff4151548d5bf6b3a36c", size = 14510 }, { url = "https://files.pythonhosted.org/packages/7a/06/a10f955f70a2e5a9bf78d11a161029d278eeacbd35ef806c3fd17b13060d/MarkupSafe-3.0.2-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:a904af0a6162c73e3edcb969eeeb53a63ceeb5d8cf642fade7d39e7963a22ddb", size = 12486 }, { url = "https://files.pythonhosted.org/packages/34/cf/65d4a571869a1a9078198ca28f39fba5fbb910f952f9dbc5220afff9f5e6/MarkupSafe-3.0.2-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4aa4e5faecf353ed117801a068ebab7b7e09ffb6e1d5e412dc852e0da018126c", size = 25480 }, { url = "https://files.pythonhosted.org/packages/0c/e3/90e9651924c430b885468b56b3d597cabf6d72be4b24a0acd1fa0e12af67/MarkupSafe-3.0.2-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c0ef13eaeee5b615fb07c9a7dadb38eac06a0608b41570d8ade51c56539e509d", size = 23914 }, { url = "https://files.pythonhosted.org/packages/66/8c/6c7cf61f95d63bb866db39085150df1f2a5bd3335298f14a66b48e92659c/MarkupSafe-3.0.2-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d16a81a06776313e817c951135cf7340a3e91e8c1ff2fac444cfd75fffa04afe", size = 23796 }, { url = "https://files.pythonhosted.org/packages/bb/35/cbe9238ec3f47ac9a7c8b3df7a808e7cb50fe149dc7039f5f454b3fba218/MarkupSafe-3.0.2-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:6381026f158fdb7c72a168278597a5e3a5222e83ea18f543112b2662a9b699c5", size = 25473 }, { url = "https://files.pythonhosted.org/packages/e6/32/7621a4382488aa283cc05e8984a9c219abad3bca087be9ec77e89939ded9/MarkupSafe-3.0.2-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:3d79d162e7be8f996986c064d1c7c817f6df3a77fe3d6859f6f9e7be4b8c213a", size = 24114 }, { url = "https://files.pythonhosted.org/packages/0d/80/0985960e4b89922cb5a0bac0ed39c5b96cbc1a536a99f30e8c220a996ed9/MarkupSafe-3.0.2-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:131a3c7689c85f5ad20f9f6fb1b866f402c445b220c19fe4308c0b147ccd2ad9", size = 24098 }, { url = "https://files.pythonhosted.org/packages/82/78/fedb03c7d5380df2427038ec8d973587e90561b2d90cd472ce9254cf348b/MarkupSafe-3.0.2-cp313-cp313t-win32.whl", hash = "sha256:ba8062ed2cf21c07a9e295d5b8a2a5ce678b913b45fdf68c32d95d6c1291e0b6", size = 15208 }, { url = "https://files.pythonhosted.org/packages/4f/65/6079a46068dfceaeabb5dcad6d674f5f5c61a6fa5673746f42a9f4c233b3/MarkupSafe-3.0.2-cp313-cp313t-win_amd64.whl", hash = "sha256:e444a31f8db13eb18ada366ab3cf45fd4b31e4db1236a4448f68778c1d1a5a2f", size = 15739 }, { url = "https://files.pythonhosted.org/packages/a7/ea/9b1530c3fdeeca613faeb0fb5cbcf2389d816072fab72a71b45749ef6062/MarkupSafe-3.0.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:eaa0a10b7f72326f1372a713e73c3f739b524b3af41feb43e4921cb529f5929a", size = 14344 }, { url = "https://files.pythonhosted.org/packages/4b/c2/fbdbfe48848e7112ab05e627e718e854d20192b674952d9042ebd8c9e5de/MarkupSafe-3.0.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:48032821bbdf20f5799ff537c7ac3d1fba0ba032cfc06194faffa8cda8b560ff", size = 12389 }, { url = "https://files.pythonhosted.org/packages/f0/25/7a7c6e4dbd4f867d95d94ca15449e91e52856f6ed1905d58ef1de5e211d0/MarkupSafe-3.0.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1a9d3f5f0901fdec14d8d2f66ef7d035f2157240a433441719ac9a3fba440b13", size = 21607 }, { url = "https://files.pythonhosted.org/packages/53/8f/f339c98a178f3c1e545622206b40986a4c3307fe39f70ccd3d9df9a9e425/MarkupSafe-3.0.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:88b49a3b9ff31e19998750c38e030fc7bb937398b1f78cfa599aaef92d693144", size = 20728 }, { url = "https://files.pythonhosted.org/packages/1a/03/8496a1a78308456dbd50b23a385c69b41f2e9661c67ea1329849a598a8f9/MarkupSafe-3.0.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:cfad01eed2c2e0c01fd0ecd2ef42c492f7f93902e39a42fc9ee1692961443a29", size = 20826 }, { url = "https://files.pythonhosted.org/packages/e6/cf/0a490a4bd363048c3022f2f475c8c05582179bb179defcee4766fb3dcc18/MarkupSafe-3.0.2-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:1225beacc926f536dc82e45f8a4d68502949dc67eea90eab715dea3a21c1b5f0", size = 21843 }, { url = "https://files.pythonhosted.org/packages/19/a3/34187a78613920dfd3cdf68ef6ce5e99c4f3417f035694074beb8848cd77/MarkupSafe-3.0.2-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:3169b1eefae027567d1ce6ee7cae382c57fe26e82775f460f0b2778beaad66c0", size = 21219 }, { url = "https://files.pythonhosted.org/packages/17/d8/5811082f85bb88410ad7e452263af048d685669bbbfb7b595e8689152498/MarkupSafe-3.0.2-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:eb7972a85c54febfb25b5c4b4f3af4dcc731994c7da0d8a0b4a6eb0640e1d178", size = 20946 }, { url = "https://files.pythonhosted.org/packages/7c/31/bd635fb5989440d9365c5e3c47556cfea121c7803f5034ac843e8f37c2f2/MarkupSafe-3.0.2-cp39-cp39-win32.whl", hash = "sha256:8c4e8c3ce11e1f92f6536ff07154f9d49677ebaaafc32db9db4620bc11ed480f", size = 15063 }, { url = "https://files.pythonhosted.org/packages/b3/73/085399401383ce949f727afec55ec3abd76648d04b9f22e1c0e99cb4bec3/MarkupSafe-3.0.2-cp39-cp39-win_amd64.whl", hash = "sha256:6e296a513ca3d94054c2c881cc913116e90fd030ad1c656b3869762b754f5f8a", size = 15506 }, ] [[package]] name = "matplotlib-inline" version = "0.1.7" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "traitlets" }, ] sdist = { url = "https://files.pythonhosted.org/packages/99/5b/a36a337438a14116b16480db471ad061c36c3694df7c2084a0da7ba538b7/matplotlib_inline-0.1.7.tar.gz", hash = "sha256:8423b23ec666be3d16e16b60bdd8ac4e86e840ebd1dd11a30b9f117f2fa0ab90", size = 8159 } wheels = [ { url = "https://files.pythonhosted.org/packages/8f/8e/9ad090d3553c280a8060fbf6e24dc1c0c29704ee7d1c372f0c174aa59285/matplotlib_inline-0.1.7-py3-none-any.whl", hash = "sha256:df192d39a4ff8f21b1895d72e6a13f5fcc5099f00fa84384e0ea28c2cc0653ca", size = 9899 }, ] [[package]] name = "mccabe" version = "0.7.0" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/e7/ff/0ffefdcac38932a54d2b5eed4e0ba8a408f215002cd178ad1df0f2806ff8/mccabe-0.7.0.tar.gz", hash = "sha256:348e0240c33b60bbdf4e523192ef919f28cb2c3d7d5c7794f74009290f236325", size = 9658 } wheels = [ { url = "https://files.pythonhosted.org/packages/27/1a/1f68f9ba0c207934b35b86a8ca3aad8395a3d6dd7921c0686e23853ff5a9/mccabe-0.7.0-py2.py3-none-any.whl", hash = "sha256:6c2d30ab6be0e4a46919781807b4f0d834ebdd6c6e3dca0bda5a15f863427b6e", size = 7350 }, ] [[package]] name = "mdurl" version = "0.1.2" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/d6/54/cfe61301667036ec958cb99bd3efefba235e65cdeb9c84d24a8293ba1d90/mdurl-0.1.2.tar.gz", hash = "sha256:bb413d29f5eea38f31dd4754dd7377d4465116fb207585f97bf925588687c1ba", size = 8729 } wheels = [ { url = "https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl", hash = "sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8", size = 9979 }, ] [[package]] name = "mergedeep" version = "1.3.4" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/3a/41/580bb4006e3ed0361b8151a01d324fb03f420815446c7def45d02f74c270/mergedeep-1.3.4.tar.gz", hash = "sha256:0096d52e9dad9939c3d975a774666af186eda617e6ca84df4c94dec30004f2a8", size = 4661 } wheels = [ { url = "https://files.pythonhosted.org/packages/2c/19/04f9b178c2d8a15b076c8b5140708fa6ffc5601fb6f1e975537072df5b2a/mergedeep-1.3.4-py3-none-any.whl", hash = "sha256:70775750742b25c0d8f36c55aed03d24c3384d17c951b3175d898bd778ef0307", size = 6354 }, ] [[package]] name = "mistune" version = "3.1.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "typing-extensions", marker = "python_full_version < '3.11'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/79/6e/96fc7cb3288666c5de2c396eb0e338dc95f7a8e4920e43e38783a22d0084/mistune-3.1.0.tar.gz", hash = "sha256:dbcac2f78292b9dc066cd03b7a3a26b62d85f8159f2ea5fd28e55df79908d667", size = 94401 } wheels = [ { url = "https://files.pythonhosted.org/packages/b4/b3/743ffc3f59da380da504d84ccd1faf9a857a1445991ff19bf2ec754163c2/mistune-3.1.0-py3-none-any.whl", hash = "sha256:b05198cf6d671b3deba6c87ec6cf0d4eb7b72c524636eddb6dbf13823b52cee1", size = 53694 }, ] [[package]] name = "mkdocs" version = "1.3.1" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "click" }, { name = "ghp-import" }, { name = "importlib-metadata" }, { name = "jinja2" }, { name = "markdown" }, { name = "mergedeep" }, { name = "packaging" }, { name = "pyyaml" }, { name = "pyyaml-env-tag" }, { name = "watchdog" }, ] sdist = { url = "https://files.pythonhosted.org/packages/52/16/2c2de8fac0437fb81d8f31558111fddcedf56eb56d90dea6ec922fcd588a/mkdocs-1.3.1.tar.gz", hash = "sha256:a41a2ff25ce3bbacc953f9844ba07d106233cd76c88bac1f59cb1564ac0d87ed", size = 3594184 } wheels = [ { url = "https://files.pythonhosted.org/packages/e4/96/6b9d87ee8a11e6d2483e3767999d4aeb8d5478d2059cfb3e21404beae470/mkdocs-1.3.1-py3-none-any.whl", hash = "sha256:fda92466393127d2da830bc6edc3a625a14b436316d1caf347690648e774c4f0", size = 3658639 }, ] [[package]] name = "mkdocs-material" version = "8.5.4" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "jinja2" }, { name = "markdown" }, { name = "mkdocs" }, { name = "mkdocs-material-extensions" }, { name = "pygments" }, { name = "pymdown-extensions" }, { name = "requests" }, ] sdist = { url = "https://files.pythonhosted.org/packages/40/37/2c7dc7cf13ad29a5d50d22ffc5e9ddabad0fccc7d5e2b06ec068272b1b4a/mkdocs_material-8.5.4.tar.gz", hash = "sha256:70dc47820d4765b77968b9119f2957d09b4d8d328d950bee4544ff224d5c7b36", size = 3474496 } wheels = [ { url = "https://files.pythonhosted.org/packages/72/13/ee77fa6a419385393a89cb885a46c76f09fa26392a1225dcb32ce540e687/mkdocs_material-8.5.4-py3-none-any.whl", hash = "sha256:aec2f0f2143109f8388aadf76e6fff749a2b74ebe730d0f674c65b53da89d19d", size = 7493997 }, ] [[package]] name = "mkdocs-material-extensions" version = "1.3.1" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/79/9b/9b4c96d6593b2a541e1cb8b34899a6d021d208bb357042823d4d2cabdbe7/mkdocs_material_extensions-1.3.1.tar.gz", hash = "sha256:10c9511cea88f568257f960358a467d12b970e1f7b2c0e5fb2bb48cab1928443", size = 11847 } wheels = [ { url = "https://files.pythonhosted.org/packages/5b/54/662a4743aa81d9582ee9339d4ffa3c8fd40a4965e033d77b9da9774d3960/mkdocs_material_extensions-1.3.1-py3-none-any.whl", hash = "sha256:adff8b62700b25cb77b53358dad940f3ef973dd6db797907c49e3c2ef3ab4e31", size = 8728 }, ] [[package]] name = "more-itertools" version = "10.6.0" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/88/3b/7fa1fe835e2e93fd6d7b52b2f95ae810cf5ba133e1845f726f5a992d62c2/more-itertools-10.6.0.tar.gz", hash = "sha256:2cd7fad1009c31cc9fb6a035108509e6547547a7a738374f10bd49a09eb3ee3b", size = 125009 } wheels = [ { url = "https://files.pythonhosted.org/packages/23/62/0fe302c6d1be1c777cab0616e6302478251dfbf9055ad426f5d0def75c89/more_itertools-10.6.0-py3-none-any.whl", hash = "sha256:6eb054cb4b6db1473f6e15fcc676a08e4732548acd47c708f0e179c2c7c01e89", size = 63038 }, ] [[package]] name = "mypy" version = "1.14.1" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "mypy-extensions" }, { name = "tomli", marker = "python_full_version < '3.11'" }, { name = "typing-extensions" }, ] sdist = { url = "https://files.pythonhosted.org/packages/b9/eb/2c92d8ea1e684440f54fa49ac5d9a5f19967b7b472a281f419e69a8d228e/mypy-1.14.1.tar.gz", hash = "sha256:7ec88144fe9b510e8475ec2f5f251992690fcf89ccb4500b214b4226abcd32d6", size = 3216051 } wheels = [ { url = "https://files.pythonhosted.org/packages/9b/7a/87ae2adb31d68402da6da1e5f30c07ea6063e9f09b5e7cfc9dfa44075e74/mypy-1.14.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:52686e37cf13d559f668aa398dd7ddf1f92c5d613e4f8cb262be2fb4fedb0fcb", size = 11211002 }, { url = "https://files.pythonhosted.org/packages/e1/23/eada4c38608b444618a132be0d199b280049ded278b24cbb9d3fc59658e4/mypy-1.14.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:1fb545ca340537d4b45d3eecdb3def05e913299ca72c290326be19b3804b39c0", size = 10358400 }, { url = "https://files.pythonhosted.org/packages/43/c9/d6785c6f66241c62fd2992b05057f404237deaad1566545e9f144ced07f5/mypy-1.14.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:90716d8b2d1f4cd503309788e51366f07c56635a3309b0f6a32547eaaa36a64d", size = 12095172 }, { url = "https://files.pythonhosted.org/packages/c3/62/daa7e787770c83c52ce2aaf1a111eae5893de9e004743f51bfcad9e487ec/mypy-1.14.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:2ae753f5c9fef278bcf12e1a564351764f2a6da579d4a81347e1d5a15819997b", size = 12828732 }, { url = "https://files.pythonhosted.org/packages/1b/a2/5fb18318a3637f29f16f4e41340b795da14f4751ef4f51c99ff39ab62e52/mypy-1.14.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:e0fe0f5feaafcb04505bcf439e991c6d8f1bf8b15f12b05feeed96e9e7bf1427", size = 13012197 }, { url = "https://files.pythonhosted.org/packages/28/99/e153ce39105d164b5f02c06c35c7ba958aaff50a2babba7d080988b03fe7/mypy-1.14.1-cp310-cp310-win_amd64.whl", hash = "sha256:7d54bd85b925e501c555a3227f3ec0cfc54ee8b6930bd6141ec872d1c572f81f", size = 9780836 }, { url = "https://files.pythonhosted.org/packages/da/11/a9422850fd506edbcdc7f6090682ecceaf1f87b9dd847f9df79942da8506/mypy-1.14.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:f995e511de847791c3b11ed90084a7a0aafdc074ab88c5a9711622fe4751138c", size = 11120432 }, { url = "https://files.pythonhosted.org/packages/b6/9e/47e450fd39078d9c02d620545b2cb37993a8a8bdf7db3652ace2f80521ca/mypy-1.14.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:d64169ec3b8461311f8ce2fd2eb5d33e2d0f2c7b49116259c51d0d96edee48d1", size = 10279515 }, { url = "https://files.pythonhosted.org/packages/01/b5/6c8d33bd0f851a7692a8bfe4ee75eb82b6983a3cf39e5e32a5d2a723f0c1/mypy-1.14.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ba24549de7b89b6381b91fbc068d798192b1b5201987070319889e93038967a8", size = 12025791 }, { url = "https://files.pythonhosted.org/packages/f0/4c/e10e2c46ea37cab5c471d0ddaaa9a434dc1d28650078ac1b56c2d7b9b2e4/mypy-1.14.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:183cf0a45457d28ff9d758730cd0210419ac27d4d3f285beda038c9083363b1f", size = 12749203 }, { url = "https://files.pythonhosted.org/packages/88/55/beacb0c69beab2153a0f57671ec07861d27d735a0faff135a494cd4f5020/mypy-1.14.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:f2a0ecc86378f45347f586e4163d1769dd81c5a223d577fe351f26b179e148b1", size = 12885900 }, { url = "https://files.pythonhosted.org/packages/a2/75/8c93ff7f315c4d086a2dfcde02f713004357d70a163eddb6c56a6a5eff40/mypy-1.14.1-cp311-cp311-win_amd64.whl", hash = "sha256:ad3301ebebec9e8ee7135d8e3109ca76c23752bac1e717bc84cd3836b4bf3eae", size = 9777869 }, { url = "https://files.pythonhosted.org/packages/43/1b/b38c079609bb4627905b74fc6a49849835acf68547ac33d8ceb707de5f52/mypy-1.14.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:30ff5ef8519bbc2e18b3b54521ec319513a26f1bba19a7582e7b1f58a6e69f14", size = 11266668 }, { url = "https://files.pythonhosted.org/packages/6b/75/2ed0d2964c1ffc9971c729f7a544e9cd34b2cdabbe2d11afd148d7838aa2/mypy-1.14.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:cb9f255c18052343c70234907e2e532bc7e55a62565d64536dbc7706a20b78b9", size = 10254060 }, { url = "https://files.pythonhosted.org/packages/a1/5f/7b8051552d4da3c51bbe8fcafffd76a6823779101a2b198d80886cd8f08e/mypy-1.14.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:8b4e3413e0bddea671012b063e27591b953d653209e7a4fa5e48759cda77ca11", size = 11933167 }, { url = "https://files.pythonhosted.org/packages/04/90/f53971d3ac39d8b68bbaab9a4c6c58c8caa4d5fd3d587d16f5927eeeabe1/mypy-1.14.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:553c293b1fbdebb6c3c4030589dab9fafb6dfa768995a453d8a5d3b23784af2e", size = 12864341 }, { url = "https://files.pythonhosted.org/packages/03/d2/8bc0aeaaf2e88c977db41583559319f1821c069e943ada2701e86d0430b7/mypy-1.14.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:fad79bfe3b65fe6a1efaed97b445c3d37f7be9fdc348bdb2d7cac75579607c89", size = 12972991 }, { url = "https://files.pythonhosted.org/packages/6f/17/07815114b903b49b0f2cf7499f1c130e5aa459411596668267535fe9243c/mypy-1.14.1-cp312-cp312-win_amd64.whl", hash = "sha256:8fa2220e54d2946e94ab6dbb3ba0a992795bd68b16dc852db33028df2b00191b", size = 9879016 }, { url = "https://files.pythonhosted.org/packages/9e/15/bb6a686901f59222275ab228453de741185f9d54fecbaacec041679496c6/mypy-1.14.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:92c3ed5afb06c3a8e188cb5da4984cab9ec9a77ba956ee419c68a388b4595255", size = 11252097 }, { url = "https://files.pythonhosted.org/packages/f8/b3/8b0f74dfd072c802b7fa368829defdf3ee1566ba74c32a2cb2403f68024c/mypy-1.14.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:dbec574648b3e25f43d23577309b16534431db4ddc09fda50841f1e34e64ed34", size = 10239728 }, { url = "https://files.pythonhosted.org/packages/c5/9b/4fd95ab20c52bb5b8c03cc49169be5905d931de17edfe4d9d2986800b52e/mypy-1.14.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:8c6d94b16d62eb3e947281aa7347d78236688e21081f11de976376cf010eb31a", size = 11924965 }, { url = "https://files.pythonhosted.org/packages/56/9d/4a236b9c57f5d8f08ed346914b3f091a62dd7e19336b2b2a0d85485f82ff/mypy-1.14.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d4b19b03fdf54f3c5b2fa474c56b4c13c9dbfb9a2db4370ede7ec11a2c5927d9", size = 12867660 }, { url = "https://files.pythonhosted.org/packages/40/88/a61a5497e2f68d9027de2bb139c7bb9abaeb1be1584649fa9d807f80a338/mypy-1.14.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:0c911fde686394753fff899c409fd4e16e9b294c24bfd5e1ea4675deae1ac6fd", size = 12969198 }, { url = "https://files.pythonhosted.org/packages/54/da/3d6fc5d92d324701b0c23fb413c853892bfe0e1dbe06c9138037d459756b/mypy-1.14.1-cp313-cp313-win_amd64.whl", hash = "sha256:8b21525cb51671219f5307be85f7e646a153e5acc656e5cebf64bfa076c50107", size = 9885276 }, { url = "https://files.pythonhosted.org/packages/ca/1f/186d133ae2514633f8558e78cd658070ba686c0e9275c5a5c24a1e1f0d67/mypy-1.14.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:3888a1816d69f7ab92092f785a462944b3ca16d7c470d564165fe703b0970c35", size = 11200493 }, { url = "https://files.pythonhosted.org/packages/af/fc/4842485d034e38a4646cccd1369f6b1ccd7bc86989c52770d75d719a9941/mypy-1.14.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:46c756a444117c43ee984bd055db99e498bc613a70bbbc120272bd13ca579fbc", size = 10357702 }, { url = "https://files.pythonhosted.org/packages/b4/e6/457b83f2d701e23869cfec013a48a12638f75b9d37612a9ddf99072c1051/mypy-1.14.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:27fc248022907e72abfd8e22ab1f10e903915ff69961174784a3900a8cba9ad9", size = 12091104 }, { url = "https://files.pythonhosted.org/packages/f1/bf/76a569158db678fee59f4fd30b8e7a0d75bcbaeef49edd882a0d63af6d66/mypy-1.14.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:499d6a72fb7e5de92218db961f1a66d5f11783f9ae549d214617edab5d4dbdbb", size = 12830167 }, { url = "https://files.pythonhosted.org/packages/43/bc/0bc6b694b3103de9fed61867f1c8bd33336b913d16831431e7cb48ef1c92/mypy-1.14.1-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:57961db9795eb566dc1d1b4e9139ebc4c6b0cb6e7254ecde69d1552bf7613f60", size = 13013834 }, { url = "https://files.pythonhosted.org/packages/b0/79/5f5ec47849b6df1e6943d5fd8e6632fbfc04b4fd4acfa5a5a9535d11b4e2/mypy-1.14.1-cp39-cp39-win_amd64.whl", hash = "sha256:07ba89fdcc9451f2ebb02853deb6aaaa3d2239a236669a63ab3801bbf923ef5c", size = 9781231 }, { url = "https://files.pythonhosted.org/packages/a0/b5/32dd67b69a16d088e533962e5044e51004176a9952419de0370cdaead0f8/mypy-1.14.1-py3-none-any.whl", hash = "sha256:b66a60cc4073aeb8ae00057f9c1f64d49e90f918fbcef9a977eb121da8b8f1d1", size = 2752905 }, ] [[package]] name = "mypy-extensions" version = "1.0.0" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/98/a4/1ab47638b92648243faf97a5aeb6ea83059cc3624972ab6b8d2316078d3f/mypy_extensions-1.0.0.tar.gz", hash = "sha256:75dbf8955dc00442a438fc4d0666508a9a97b6bd41aa2f0ffe9d2f2725af0782", size = 4433 } wheels = [ { url = "https://files.pythonhosted.org/packages/2a/e2/5d3f6ada4297caebe1a2add3b126fe800c96f56dbe5d1988a2cbe0b267aa/mypy_extensions-1.0.0-py3-none-any.whl", hash = "sha256:4392f6c0eb8a5668a69e23d168ffa70f0be9ccfd32b5cc2d26a34ae5b844552d", size = 4695 }, ] [[package]] name = "natsort" version = "8.4.0" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/e2/a9/a0c57aee75f77794adaf35322f8b6404cbd0f89ad45c87197a937764b7d0/natsort-8.4.0.tar.gz", hash = "sha256:45312c4a0e5507593da193dedd04abb1469253b601ecaf63445ad80f0a1ea581", size = 76575 } wheels = [ { url = "https://files.pythonhosted.org/packages/ef/82/7a9d0550484a62c6da82858ee9419f3dd1ccc9aa1c26a1e43da3ecd20b0d/natsort-8.4.0-py3-none-any.whl", hash = "sha256:4732914fb471f56b5cce04d7bae6f164a592c7712e1c85f9ef585e197299521c", size = 38268 }, ] [[package]] name = "nbclient" version = "0.10.2" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "jupyter-client" }, { name = "jupyter-core" }, { name = "nbformat" }, { name = "traitlets" }, ] sdist = { url = "https://files.pythonhosted.org/packages/87/66/7ffd18d58eae90d5721f9f39212327695b749e23ad44b3881744eaf4d9e8/nbclient-0.10.2.tar.gz", hash = "sha256:90b7fc6b810630db87a6d0c2250b1f0ab4cf4d3c27a299b0cde78a4ed3fd9193", size = 62424 } wheels = [ { url = "https://files.pythonhosted.org/packages/34/6d/e7fa07f03a4a7b221d94b4d586edb754a9b0dc3c9e2c93353e9fa4e0d117/nbclient-0.10.2-py3-none-any.whl", hash = "sha256:4ffee11e788b4a27fabeb7955547e4318a5298f34342a4bfd01f2e1faaeadc3d", size = 25434 }, ] [[package]] name = "nbconvert" version = "7.16.5" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "beautifulsoup4" }, { name = "bleach", extra = ["css"] }, { name = "defusedxml" }, { name = "importlib-metadata", marker = "python_full_version < '3.10'" }, { name = "jinja2" }, { name = "jupyter-core" }, { name = "jupyterlab-pygments" }, { name = "markupsafe" }, { name = "mistune" }, { name = "nbclient" }, { name = "nbformat" }, { name = "packaging" }, { name = "pandocfilters" }, { name = "pygments" }, { name = "traitlets" }, ] sdist = { url = "https://files.pythonhosted.org/packages/46/2c/d026c0367f2be2463d4c2f5b538e28add2bc67bc13730abb7f364ae4eb8b/nbconvert-7.16.5.tar.gz", hash = "sha256:c83467bb5777fdfaac5ebbb8e864f300b277f68692ecc04d6dab72f2d8442344", size = 856367 } wheels = [ { url = "https://files.pythonhosted.org/packages/8f/9e/2dcc9fe00cf55d95a8deae69384e9cea61816126e345754f6c75494d32ec/nbconvert-7.16.5-py3-none-any.whl", hash = "sha256:e12eac052d6fd03040af4166c563d76e7aeead2e9aadf5356db552a1784bd547", size = 258061 }, ] [[package]] name = "nbformat" version = "5.10.4" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "fastjsonschema" }, { name = "jsonschema" }, { name = "jupyter-core" }, { name = "traitlets" }, ] sdist = { url = "https://files.pythonhosted.org/packages/6d/fd/91545e604bc3dad7dca9ed03284086039b294c6b3d75c0d2fa45f9e9caf3/nbformat-5.10.4.tar.gz", hash = "sha256:322168b14f937a5d11362988ecac2a4952d3d8e3a2cbeb2319584631226d5b3a", size = 142749 } wheels = [ { url = "https://files.pythonhosted.org/packages/a9/82/0340caa499416c78e5d8f5f05947ae4bc3cba53c9f038ab6e9ed964e22f1/nbformat-5.10.4-py3-none-any.whl", hash = "sha256:3b48d6c8fbca4b299bf3982ea7db1af21580e4fec269ad087b9e81588891200b", size = 78454 }, ] [[package]] name = "nodeenv" version = "1.9.1" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/43/16/fc88b08840de0e0a72a2f9d8c6bae36be573e475a6326ae854bcc549fc45/nodeenv-1.9.1.tar.gz", hash = "sha256:6ec12890a2dab7946721edbfbcd91f3319c6ccc9aec47be7c7e6b7011ee6645f", size = 47437 } wheels = [ { url = "https://files.pythonhosted.org/packages/d2/1d/1b658dbd2b9fa9c4c9f32accbfc0205d532c8c6194dc0f2a4c0428e7128a/nodeenv-1.9.1-py2.py3-none-any.whl", hash = "sha256:ba11c9782d29c27c70ffbdda2d7415098754709be8a7056d79a737cd901155c9", size = 22314 }, ] [[package]] name = "packaging" version = "24.2" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/d0/63/68dbb6eb2de9cb10ee4c9c14a0148804425e13c4fb20d61cce69f53106da/packaging-24.2.tar.gz", hash = "sha256:c228a6dc5e932d346bc5739379109d49e8853dd8223571c7c5b55260edc0b97f", size = 163950 } wheels = [ { url = "https://files.pythonhosted.org/packages/88/ef/eb23f262cca3c0c4eb7ab1933c3b1f03d021f2c48f54763065b6f0e321be/packaging-24.2-py3-none-any.whl", hash = "sha256:09abb1bccd265c01f4a3aa3f7a7db064b36514d2cba19a2f694fe6150451a759", size = 65451 }, ] [[package]] name = "pandocfilters" version = "1.5.1" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/70/6f/3dd4940bbe001c06a65f88e36bad298bc7a0de5036115639926b0c5c0458/pandocfilters-1.5.1.tar.gz", hash = "sha256:002b4a555ee4ebc03f8b66307e287fa492e4a77b4ea14d3f934328297bb4939e", size = 8454 } wheels = [ { url = "https://files.pythonhosted.org/packages/ef/af/4fbc8cab944db5d21b7e2a5b8e9211a03a79852b1157e2c102fcc61ac440/pandocfilters-1.5.1-py2.py3-none-any.whl", hash = "sha256:93be382804a9cdb0a7267585f157e5d1731bbe5545a85b268d6f5fe6232de2bc", size = 8663 }, ] [[package]] name = "parso" version = "0.8.4" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/66/94/68e2e17afaa9169cf6412ab0f28623903be73d1b32e208d9e8e541bb086d/parso-0.8.4.tar.gz", hash = "sha256:eb3a7b58240fb99099a345571deecc0f9540ea5f4dd2fe14c2a99d6b281ab92d", size = 400609 } wheels = [ { url = "https://files.pythonhosted.org/packages/c6/ac/dac4a63f978e4dcb3c6d3a78c4d8e0192a113d288502a1216950c41b1027/parso-0.8.4-py2.py3-none-any.whl", hash = "sha256:a418670a20291dacd2dddc80c377c5c3791378ee1e8d12bffc35420643d43f18", size = 103650 }, ] [[package]] name = "pathspec" version = "0.12.1" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/ca/bc/f35b8446f4531a7cb215605d100cd88b7ac6f44ab3fc94870c120ab3adbf/pathspec-0.12.1.tar.gz", hash = "sha256:a482d51503a1ab33b1c67a6c3813a26953dbdc71c31dacaef9a838c4e29f5712", size = 51043 } wheels = [ { url = "https://files.pythonhosted.org/packages/cc/20/ff623b09d963f88bfde16306a54e12ee5ea43e9b597108672ff3a408aad6/pathspec-0.12.1-py3-none-any.whl", hash = "sha256:a0d503e138a4c123b27490a4f7beda6a01c6f288df0e4a8b79c7eb0dc7b4cc08", size = 31191 }, ] [[package]] name = "pbr" version = "6.1.0" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/b2/35/80cf8f6a4f34017a7fe28242dc45161a1baa55c41563c354d8147e8358b2/pbr-6.1.0.tar.gz", hash = "sha256:788183e382e3d1d7707db08978239965e8b9e4e5ed42669bf4758186734d5f24", size = 124032 } wheels = [ { url = "https://files.pythonhosted.org/packages/1d/44/6a65ecd630393d47ad3e7d5354768cb7f9a10b3a0eb2cd8c6f52b28211ee/pbr-6.1.0-py2.py3-none-any.whl", hash = "sha256:a776ae228892d8013649c0aeccbb3d5f99ee15e005a4cbb7e61d55a067b28a2a", size = 108529 }, ] [[package]] name = "pdocs" version = "1.2.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "docstring-parser" }, { name = "hug" }, { name = "mako" }, { name = "markdown" }, ] sdist = { url = "https://files.pythonhosted.org/packages/80/55/2aca02c7015f52e30fb7ce920b967276c1a4198812db703e322a0ed43390/pdocs-1.2.0.tar.gz", hash = "sha256:996ad4d5039b59a9a112d29abfb3995ec4ed8d8415ddce6947c3a5248adb428b", size = 33378 } wheels = [ { url = "https://files.pythonhosted.org/packages/c8/9f/06545fcae3e8b4819101894c4d22a7765e88a94f724d5ac2af0c6a976eb4/pdocs-1.2.0-py3-none-any.whl", hash = "sha256:caca2829415e62d31eaab46c53cd77a2a14f132c73e48e25187331c3a9fc2459", size = 35529 }, ] [[package]] name = "pep517" version = "0.13.1" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "tomli", marker = "python_full_version < '3.11'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/44/d7/8f5d2be1a5fed3b0b5ccd3e800153c0f4dd84c2a688d25bce0bb0cb1f87f/pep517-0.13.1.tar.gz", hash = "sha256:1b2fa2ffd3938bb4beffe5d6146cbcb2bda996a5a4da9f31abffd8b24e07b317", size = 26176 } wheels = [ { url = "https://files.pythonhosted.org/packages/25/6e/ca4a5434eb0e502210f591b97537d322546e4833dcb4d470a48c375c5540/pep517-0.13.1-py3-none-any.whl", hash = "sha256:31b206f67165b3536dd577c5c3f1518e8fbaf38cbc57efff8369a392feff1721", size = 19072 }, ] [[package]] name = "pep8-naming" version = "0.14.1" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "flake8" }, ] sdist = { url = "https://files.pythonhosted.org/packages/be/8e/1de32e908d8b008bb9352bfe7749aedecb71e2793d36c7ee342716acd1ec/pep8-naming-0.14.1.tar.gz", hash = "sha256:1ef228ae80875557eb6c1549deafed4dabbf3261cfcafa12f773fe0db9be8a36", size = 16546 } wheels = [ { url = "https://files.pythonhosted.org/packages/ec/a2/450b71d1a87fcee50a7b994a53b1c68fc6a6b718df0eb035f2bffb2d3a4f/pep8_naming-0.14.1-py3-none-any.whl", hash = "sha256:63f514fc777d715f935faf185dedd679ab99526a7f2f503abb61587877f7b1c5", size = 8859 }, ] [[package]] name = "pexpect" version = "4.9.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "ptyprocess" }, ] sdist = { url = "https://files.pythonhosted.org/packages/42/92/cc564bf6381ff43ce1f4d06852fc19a2f11d180f23dc32d9588bee2f149d/pexpect-4.9.0.tar.gz", hash = "sha256:ee7d41123f3c9911050ea2c2dac107568dc43b2d3b0c7557a33212c398ead30f", size = 166450 } wheels = [ { url = "https://files.pythonhosted.org/packages/9e/c3/059298687310d527a58bb01f3b1965787ee3b40dce76752eda8b44e9a2c5/pexpect-4.9.0-py2.py3-none-any.whl", hash = "sha256:7236d1e080e4936be2dc3e326cec0af72acf9212a7e1d060210e70a47e253523", size = 63772 }, ] [[package]] name = "pickleshare" version = "0.7.5" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/d8/b6/df3c1c9b616e9c0edbc4fbab6ddd09df9535849c64ba51fcb6531c32d4d8/pickleshare-0.7.5.tar.gz", hash = "sha256:87683d47965c1da65cdacaf31c8441d12b8044cdec9aca500cd78fc2c683afca", size = 6161 } wheels = [ { url = "https://files.pythonhosted.org/packages/9a/41/220f49aaea88bc6fa6cba8d05ecf24676326156c23b991e80b3f2fc24c77/pickleshare-0.7.5-py2.py3-none-any.whl", hash = "sha256:9649af414d74d4df115d5d718f82acb59c9d418196b7b4290ed47a12ce62df56", size = 6877 }, ] [[package]] name = "pip" version = "24.3.1" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/f4/b1/b422acd212ad7eedddaf7981eee6e5de085154ff726459cf2da7c5a184c1/pip-24.3.1.tar.gz", hash = "sha256:ebcb60557f2aefabc2e0f918751cd24ea0d56d8ec5445fe1807f1d2109660b99", size = 1931073 } wheels = [ { url = "https://files.pythonhosted.org/packages/ef/7d/500c9ad20238fcfcb4cb9243eede163594d7020ce87bd9610c9e02771876/pip-24.3.1-py3-none-any.whl", hash = "sha256:3790624780082365f47549d032f3770eeb2b1e8bd1f7b2e02dace1afa361b4ed", size = 1822182 }, ] [[package]] name = "pip-api" version = "0.0.34" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "pip" }, ] sdist = { url = "https://files.pythonhosted.org/packages/b9/f1/ee85f8c7e82bccf90a3c7aad22863cc6e20057860a1361083cd2adacb92e/pip_api-0.0.34.tar.gz", hash = "sha256:9b75e958f14c5a2614bae415f2adf7eeb54d50a2cfbe7e24fd4826471bac3625", size = 123017 } wheels = [ { url = "https://files.pythonhosted.org/packages/91/f7/ebf5003e1065fd00b4cbef53bf0a65c3d3e1b599b676d5383ccb7a8b88ba/pip_api-0.0.34-py3-none-any.whl", hash = "sha256:8b2d7d7c37f2447373aa2cf8b1f60a2f2b27a84e1e9e0294a3f6ef10eb3ba6bb", size = 120369 }, ] [[package]] name = "pipreqs" version = "0.5.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "docopt" }, { name = "ipython" }, { name = "nbconvert" }, { name = "yarg" }, ] sdist = { url = "https://files.pythonhosted.org/packages/12/4c/0a335b1b70c7e1821140ac6f884b51d47f049bcb600fa19bb374922f73aa/pipreqs-0.5.0.tar.gz", hash = "sha256:f33298d235ff76def369cb9a3594d084d9badc70cebba1e8cb271fcd4fdc0183", size = 35240 } wheels = [ { url = "https://files.pythonhosted.org/packages/36/38/cc1343c3a63655e18328e51e00c6e6851be648f1b8babffc5131f1b9f226/pipreqs-0.5.0-py3-none-any.whl", hash = "sha256:0809f6217028e35785f80e90217e18043e58c99ba28175e28320f9074dd03874", size = 33496 }, ] [[package]] name = "platformdirs" version = "4.3.6" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/13/fc/128cc9cb8f03208bdbf93d3aa862e16d376844a14f9a0ce5cf4507372de4/platformdirs-4.3.6.tar.gz", hash = "sha256:357fb2acbc885b0419afd3ce3ed34564c13c9b95c89360cd9563f73aa5e2b907", size = 21302 } wheels = [ { url = "https://files.pythonhosted.org/packages/3c/a6/bc1012356d8ece4d66dd75c4b9fc6c1f6650ddd5991e421177d9f8f671be/platformdirs-4.3.6-py3-none-any.whl", hash = "sha256:73e575e1408ab8103900836b97580d5307456908a03e92031bab39e4554cc3fb", size = 18439 }, ] [[package]] name = "plette" version = "2.1.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "tomlkit" }, ] sdist = { url = "https://files.pythonhosted.org/packages/e2/f9/27e6bcd716fa24aacc2f69fc30b2203ca105300c2c300935dce26173acce/plette-2.1.0.tar.gz", hash = "sha256:0e9898513eacbcf06c6b05e9e042a7733cfb2030335532044b9b3ff84431821c", size = 12908 } wheels = [ { url = "https://files.pythonhosted.org/packages/e2/5c/d6b9b61c13c47a6f3789cb1f8a3de34017e3d9f1f781fb17352003f21005/plette-2.1.0-py2.py3-none-any.whl", hash = "sha256:65cea1259d69339e518481c9f59130cea2a6f712117bee340bc4c1c10e47f9e7", size = 12377 }, ] [package.optional-dependencies] validation = [ { name = "cerberus" }, ] [[package]] name = "pluggy" version = "1.5.0" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/96/2d/02d4312c973c6050a18b314a5ad0b3210edb65a906f868e31c111dede4a6/pluggy-1.5.0.tar.gz", hash = "sha256:2cffa88e94fdc978c4c574f15f9e59b7f4201d439195c3715ca9e2486f1d0cf1", size = 67955 } wheels = [ { url = "https://files.pythonhosted.org/packages/88/5f/e351af9a41f866ac3f1fac4ca0613908d9a41741cfcf2228f4ad853b697d/pluggy-1.5.0-py3-none-any.whl", hash = "sha256:44e1ad92c8ca002de6377e165f3e0f1be63266ab4d554740532335b9d75ea669", size = 20556 }, ] [[package]] name = "portray" version = "1.8.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "gitpython" }, { name = "hug" }, { name = "livereload" }, { name = "mkdocs" }, { name = "mkdocs-material" }, { name = "pdocs" }, { name = "pymdown-extensions" }, { name = "toml" }, { name = "yaspin" }, ] sdist = { url = "https://files.pythonhosted.org/packages/31/c5/647feff9c1a65c403594e51e8ebc9eb93b71e77808c159cf688970585715/portray-1.8.0.tar.gz", hash = "sha256:a9dd2973a0235051c5b68a29390c3eeee192dc248cc2d944452ee9c02423b47d", size = 13590 } wheels = [ { url = "https://files.pythonhosted.org/packages/31/99/73ee12584f7186b99ce07f130a1f8b727e72008f4f767552c227ff1a5fb7/portray-1.8.0-py3-none-any.whl", hash = "sha256:c7ee981b51f9b41b60b04c1351e1b61edd291049d10c45f7c8f05897caa6a931", size = 14211 }, ] [[package]] name = "pre-commit" version = "4.1.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "cfgv" }, { name = "identify" }, { name = "nodeenv" }, { name = "pyyaml" }, { name = "virtualenv" }, ] sdist = { url = "https://files.pythonhosted.org/packages/2a/13/b62d075317d8686071eb843f0bb1f195eb332f48869d3c31a4c6f1e063ac/pre_commit-4.1.0.tar.gz", hash = "sha256:ae3f018575a588e30dfddfab9a05448bfbd6b73d78709617b5a2b853549716d4", size = 193330 } wheels = [ { url = "https://files.pythonhosted.org/packages/43/b3/df14c580d82b9627d173ceea305ba898dca135feb360b6d84019d0803d3b/pre_commit-4.1.0-py2.py3-none-any.whl", hash = "sha256:d29e7cb346295bcc1cc75fc3e92e343495e3ea0196c9ec6ba53f49f10ab6ae7b", size = 220560 }, ] [[package]] name = "prompt-toolkit" version = "3.0.50" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "wcwidth" }, ] sdist = { url = "https://files.pythonhosted.org/packages/a1/e1/bd15cb8ffdcfeeb2bdc215de3c3cffca11408d829e4b8416dcfe71ba8854/prompt_toolkit-3.0.50.tar.gz", hash = "sha256:544748f3860a2623ca5cd6d2795e7a14f3d0e1c3c9728359013f79877fc89bab", size = 429087 } wheels = [ { url = "https://files.pythonhosted.org/packages/e4/ea/d836f008d33151c7a1f62caf3d8dd782e4d15f6a43897f64480c2b8de2ad/prompt_toolkit-3.0.50-py3-none-any.whl", hash = "sha256:9b6427eb19e479d98acff65196a307c555eb567989e6d88ebbb1b509d9779198", size = 387816 }, ] [[package]] name = "ptyprocess" version = "0.7.0" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/20/e5/16ff212c1e452235a90aeb09066144d0c5a6a8c0834397e03f5224495c4e/ptyprocess-0.7.0.tar.gz", hash = "sha256:5c5d0a3b48ceee0b48485e0c26037c0acd7d29765ca3fbb5cb3831d347423220", size = 70762 } wheels = [ { url = "https://files.pythonhosted.org/packages/22/a6/858897256d0deac81a172289110f31629fc4cee19b6f01283303e18c8db3/ptyprocess-0.7.0-py2.py3-none-any.whl", hash = "sha256:4b41f3967fce3af57cc7e94b888626c18bf37a083e3651ca8feeb66d492fef35", size = 13993 }, ] [[package]] name = "pure-eval" version = "0.2.3" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/cd/05/0a34433a064256a578f1783a10da6df098ceaa4a57bbeaa96a6c0352786b/pure_eval-0.2.3.tar.gz", hash = "sha256:5f4e983f40564c576c7c8635ae88db5956bb2229d7e9237d03b3c0b0190eaf42", size = 19752 } wheels = [ { url = "https://files.pythonhosted.org/packages/8e/37/efad0257dc6e593a18957422533ff0f87ede7c9c6ea010a2177d738fb82f/pure_eval-0.2.3-py3-none-any.whl", hash = "sha256:1db8e35b67b3d218d818ae653e27f06c3aa420901fa7b081ca98cbedc874e0d0", size = 11842 }, ] [[package]] name = "py-cpuinfo" version = "9.0.0" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/37/a8/d832f7293ebb21690860d2e01d8115e5ff6f2ae8bbdc953f0eb0fa4bd2c7/py-cpuinfo-9.0.0.tar.gz", hash = "sha256:3cdbbf3fac90dc6f118bfd64384f309edeadd902d7c8fb17f02ffa1fc3f49690", size = 104716 } wheels = [ { url = "https://files.pythonhosted.org/packages/e0/a9/023730ba63db1e494a271cb018dcd361bd2c917ba7004c3e49d5daf795a2/py_cpuinfo-9.0.0-py3-none-any.whl", hash = "sha256:859625bc251f64e21f077d099d4162689c762b5d6a4c3c97553d56241c9674d5", size = 22335 }, ] [[package]] name = "pycodestyle" version = "2.11.1" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/34/8f/fa09ae2acc737b9507b5734a9aec9a2b35fa73409982f57db1b42f8c3c65/pycodestyle-2.11.1.tar.gz", hash = "sha256:41ba0e7afc9752dfb53ced5489e89f8186be00e599e712660695b7a75ff2663f", size = 38974 } wheels = [ { url = "https://files.pythonhosted.org/packages/b1/90/a998c550d0ddd07e38605bb5c455d00fcc177a800ff9cc3dafdcb3dd7b56/pycodestyle-2.11.1-py2.py3-none-any.whl", hash = "sha256:44fe31000b2d866f2e41841b18528a505fbd7fef9017b04eff4e2648a0fadc67", size = 31132 }, ] [[package]] name = "pycparser" version = "2.22" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/1d/b2/31537cf4b1ca988837256c910a668b553fceb8f069bedc4b1c826024b52c/pycparser-2.22.tar.gz", hash = "sha256:491c8be9c040f5390f5bf44a5b07752bd07f56edf992381b05c701439eec10f6", size = 172736 } wheels = [ { url = "https://files.pythonhosted.org/packages/13/a3/a812df4e2dd5696d1f351d58b8fe16a405b234ad2886a0dab9183fb78109/pycparser-2.22-py3-none-any.whl", hash = "sha256:c3702b6d3dd8c7abc1afa565d7e63d53a1d0bd86cdc24edd75470f4de499cfcc", size = 117552 }, ] [[package]] name = "pydantic" version = "2.9.2" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "annotated-types" }, { name = "pydantic-core" }, { name = "typing-extensions" }, ] sdist = { url = "https://files.pythonhosted.org/packages/a9/b7/d9e3f12af310e1120c21603644a1cd86f59060e040ec5c3a80b8f05fae30/pydantic-2.9.2.tar.gz", hash = "sha256:d155cef71265d1e9807ed1c32b4c8deec042a44a50a4188b25ac67ecd81a9c0f", size = 769917 } wheels = [ { url = "https://files.pythonhosted.org/packages/df/e4/ba44652d562cbf0bf320e0f3810206149c8a4e99cdbf66da82e97ab53a15/pydantic-2.9.2-py3-none-any.whl", hash = "sha256:f048cec7b26778210e28a0459867920654d48e5e62db0958433636cde4254f12", size = 434928 }, ] [[package]] name = "pydantic-core" version = "2.23.4" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "typing-extensions" }, ] sdist = { url = "https://files.pythonhosted.org/packages/e2/aa/6b6a9b9f8537b872f552ddd46dd3da230367754b6f707b8e1e963f515ea3/pydantic_core-2.23.4.tar.gz", hash = "sha256:2584f7cf844ac4d970fba483a717dbe10c1c1c96a969bf65d61ffe94df1b2863", size = 402156 } wheels = [ { url = "https://files.pythonhosted.org/packages/5c/8b/d3ae387f66277bd8104096d6ec0a145f4baa2966ebb2cad746c0920c9526/pydantic_core-2.23.4-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:b10bd51f823d891193d4717448fab065733958bdb6a6b351967bd349d48d5c9b", size = 1867835 }, { url = "https://files.pythonhosted.org/packages/46/76/f68272e4c3a7df8777798282c5e47d508274917f29992d84e1898f8908c7/pydantic_core-2.23.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:4fc714bdbfb534f94034efaa6eadd74e5b93c8fa6315565a222f7b6f42ca1166", size = 1776689 }, { url = "https://files.pythonhosted.org/packages/cc/69/5f945b4416f42ea3f3bc9d2aaec66c76084a6ff4ff27555bf9415ab43189/pydantic_core-2.23.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:63e46b3169866bd62849936de036f901a9356e36376079b05efa83caeaa02ceb", size = 1800748 }, { url = "https://files.pythonhosted.org/packages/50/ab/891a7b0054bcc297fb02d44d05c50e68154e31788f2d9d41d0b72c89fdf7/pydantic_core-2.23.4-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ed1a53de42fbe34853ba90513cea21673481cd81ed1be739f7f2efb931b24916", size = 1806469 }, { url = "https://files.pythonhosted.org/packages/31/7c/6e3fa122075d78f277a8431c4c608f061881b76c2b7faca01d317ee39b5d/pydantic_core-2.23.4-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:cfdd16ab5e59fc31b5e906d1a3f666571abc367598e3e02c83403acabc092e07", size = 2002246 }, { url = "https://files.pythonhosted.org/packages/ad/6f/22d5692b7ab63fc4acbc74de6ff61d185804a83160adba5e6cc6068e1128/pydantic_core-2.23.4-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:255a8ef062cbf6674450e668482456abac99a5583bbafb73f9ad469540a3a232", size = 2659404 }, { url = "https://files.pythonhosted.org/packages/11/ac/1e647dc1121c028b691028fa61a4e7477e6aeb5132628fde41dd34c1671f/pydantic_core-2.23.4-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4a7cd62e831afe623fbb7aabbb4fe583212115b3ef38a9f6b71869ba644624a2", size = 2053940 }, { url = "https://files.pythonhosted.org/packages/91/75/984740c17f12c3ce18b5a2fcc4bdceb785cce7df1511a4ce89bca17c7e2d/pydantic_core-2.23.4-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:f09e2ff1f17c2b51f2bc76d1cc33da96298f0a036a137f5440ab3ec5360b624f", size = 1921437 }, { url = "https://files.pythonhosted.org/packages/a0/74/13c5f606b64d93f0721e7768cd3e8b2102164866c207b8cd6f90bb15d24f/pydantic_core-2.23.4-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:e38e63e6f3d1cec5a27e0afe90a085af8b6806ee208b33030e65b6516353f1a3", size = 1966129 }, { url = "https://files.pythonhosted.org/packages/18/03/9c4aa5919457c7b57a016c1ab513b1a926ed9b2bb7915bf8e506bf65c34b/pydantic_core-2.23.4-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:0dbd8dbed2085ed23b5c04afa29d8fd2771674223135dc9bc937f3c09284d071", size = 2110908 }, { url = "https://files.pythonhosted.org/packages/92/2c/053d33f029c5dc65e5cf44ff03ceeefb7cce908f8f3cca9265e7f9b540c8/pydantic_core-2.23.4-cp310-none-win32.whl", hash = "sha256:6531b7ca5f951d663c339002e91aaebda765ec7d61b7d1e3991051906ddde119", size = 1735278 }, { url = "https://files.pythonhosted.org/packages/de/81/7dfe464eca78d76d31dd661b04b5f2036ec72ea8848dd87ab7375e185c23/pydantic_core-2.23.4-cp310-none-win_amd64.whl", hash = "sha256:7c9129eb40958b3d4500fa2467e6a83356b3b61bfff1b414c7361d9220f9ae8f", size = 1917453 }, { url = "https://files.pythonhosted.org/packages/5d/30/890a583cd3f2be27ecf32b479d5d615710bb926d92da03e3f7838ff3e58b/pydantic_core-2.23.4-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:77733e3892bb0a7fa797826361ce8a9184d25c8dffaec60b7ffe928153680ba8", size = 1865160 }, { url = "https://files.pythonhosted.org/packages/1d/9a/b634442e1253bc6889c87afe8bb59447f106ee042140bd57680b3b113ec7/pydantic_core-2.23.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:1b84d168f6c48fabd1f2027a3d1bdfe62f92cade1fb273a5d68e621da0e44e6d", size = 1776777 }, { url = "https://files.pythonhosted.org/packages/75/9a/7816295124a6b08c24c96f9ce73085032d8bcbaf7e5a781cd41aa910c891/pydantic_core-2.23.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:df49e7a0861a8c36d089c1ed57d308623d60416dab2647a4a17fe050ba85de0e", size = 1799244 }, { url = "https://files.pythonhosted.org/packages/a9/8f/89c1405176903e567c5f99ec53387449e62f1121894aa9fc2c4fdc51a59b/pydantic_core-2.23.4-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ff02b6d461a6de369f07ec15e465a88895f3223eb75073ffea56b84d9331f607", size = 1805307 }, { url = "https://files.pythonhosted.org/packages/d5/a5/1a194447d0da1ef492e3470680c66048fef56fc1f1a25cafbea4bc1d1c48/pydantic_core-2.23.4-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:996a38a83508c54c78a5f41456b0103c30508fed9abcad0a59b876d7398f25fd", size = 2000663 }, { url = "https://files.pythonhosted.org/packages/13/a5/1df8541651de4455e7d587cf556201b4f7997191e110bca3b589218745a5/pydantic_core-2.23.4-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d97683ddee4723ae8c95d1eddac7c192e8c552da0c73a925a89fa8649bf13eea", size = 2655941 }, { url = "https://files.pythonhosted.org/packages/44/31/a3899b5ce02c4316865e390107f145089876dff7e1dfc770a231d836aed8/pydantic_core-2.23.4-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:216f9b2d7713eb98cb83c80b9c794de1f6b7e3145eef40400c62e86cee5f4e1e", size = 2052105 }, { url = "https://files.pythonhosted.org/packages/1b/aa/98e190f8745d5ec831f6d5449344c48c0627ac5fed4e5340a44b74878f8e/pydantic_core-2.23.4-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:6f783e0ec4803c787bcea93e13e9932edab72068f68ecffdf86a99fd5918878b", size = 1919967 }, { url = "https://files.pythonhosted.org/packages/ae/35/b6e00b6abb2acfee3e8f85558c02a0822e9a8b2f2d812ea8b9079b118ba0/pydantic_core-2.23.4-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:d0776dea117cf5272382634bd2a5c1b6eb16767c223c6a5317cd3e2a757c61a0", size = 1964291 }, { url = "https://files.pythonhosted.org/packages/13/46/7bee6d32b69191cd649bbbd2361af79c472d72cb29bb2024f0b6e350ba06/pydantic_core-2.23.4-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:d5f7a395a8cf1621939692dba2a6b6a830efa6b3cee787d82c7de1ad2930de64", size = 2109666 }, { url = "https://files.pythonhosted.org/packages/39/ef/7b34f1b122a81b68ed0a7d0e564da9ccdc9a2924c8d6c6b5b11fa3a56970/pydantic_core-2.23.4-cp311-none-win32.whl", hash = "sha256:74b9127ffea03643e998e0c5ad9bd3811d3dac8c676e47db17b0ee7c3c3bf35f", size = 1732940 }, { url = "https://files.pythonhosted.org/packages/2f/76/37b7e76c645843ff46c1d73e046207311ef298d3f7b2f7d8f6ac60113071/pydantic_core-2.23.4-cp311-none-win_amd64.whl", hash = "sha256:98d134c954828488b153d88ba1f34e14259284f256180ce659e8d83e9c05eaa3", size = 1916804 }, { url = "https://files.pythonhosted.org/packages/74/7b/8e315f80666194b354966ec84b7d567da77ad927ed6323db4006cf915f3f/pydantic_core-2.23.4-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:f3e0da4ebaef65158d4dfd7d3678aad692f7666877df0002b8a522cdf088f231", size = 1856459 }, { url = "https://files.pythonhosted.org/packages/14/de/866bdce10ed808323d437612aca1ec9971b981e1c52e5e42ad9b8e17a6f6/pydantic_core-2.23.4-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:f69a8e0b033b747bb3e36a44e7732f0c99f7edd5cea723d45bc0d6e95377ffee", size = 1770007 }, { url = "https://files.pythonhosted.org/packages/dc/69/8edd5c3cd48bb833a3f7ef9b81d7666ccddd3c9a635225214e044b6e8281/pydantic_core-2.23.4-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:723314c1d51722ab28bfcd5240d858512ffd3116449c557a1336cbe3919beb87", size = 1790245 }, { url = "https://files.pythonhosted.org/packages/80/33/9c24334e3af796ce80d2274940aae38dd4e5676298b4398eff103a79e02d/pydantic_core-2.23.4-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:bb2802e667b7051a1bebbfe93684841cc9351004e2badbd6411bf357ab8d5ac8", size = 1801260 }, { url = "https://files.pythonhosted.org/packages/a5/6f/e9567fd90104b79b101ca9d120219644d3314962caa7948dd8b965e9f83e/pydantic_core-2.23.4-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d18ca8148bebe1b0a382a27a8ee60350091a6ddaf475fa05ef50dc35b5df6327", size = 1996872 }, { url = "https://files.pythonhosted.org/packages/2d/ad/b5f0fe9e6cfee915dd144edbd10b6e9c9c9c9d7a56b69256d124b8ac682e/pydantic_core-2.23.4-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:33e3d65a85a2a4a0dc3b092b938a4062b1a05f3a9abde65ea93b233bca0e03f2", size = 2661617 }, { url = "https://files.pythonhosted.org/packages/06/c8/7d4b708f8d05a5cbfda3243aad468052c6e99de7d0937c9146c24d9f12e9/pydantic_core-2.23.4-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:128585782e5bfa515c590ccee4b727fb76925dd04a98864182b22e89a4e6ed36", size = 2071831 }, { url = "https://files.pythonhosted.org/packages/89/4d/3079d00c47f22c9a9a8220db088b309ad6e600a73d7a69473e3a8e5e3ea3/pydantic_core-2.23.4-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:68665f4c17edcceecc112dfed5dbe6f92261fb9d6054b47d01bf6371a6196126", size = 1917453 }, { url = "https://files.pythonhosted.org/packages/e9/88/9df5b7ce880a4703fcc2d76c8c2d8eb9f861f79d0c56f4b8f5f2607ccec8/pydantic_core-2.23.4-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:20152074317d9bed6b7a95ade3b7d6054845d70584216160860425f4fbd5ee9e", size = 1968793 }, { url = "https://files.pythonhosted.org/packages/e3/b9/41f7efe80f6ce2ed3ee3c2dcfe10ab7adc1172f778cc9659509a79518c43/pydantic_core-2.23.4-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:9261d3ce84fa1d38ed649c3638feefeae23d32ba9182963e465d58d62203bd24", size = 2116872 }, { url = "https://files.pythonhosted.org/packages/63/08/b59b7a92e03dd25554b0436554bf23e7c29abae7cce4b1c459cd92746811/pydantic_core-2.23.4-cp312-none-win32.whl", hash = "sha256:4ba762ed58e8d68657fc1281e9bb72e1c3e79cc5d464be146e260c541ec12d84", size = 1738535 }, { url = "https://files.pythonhosted.org/packages/88/8d/479293e4d39ab409747926eec4329de5b7129beaedc3786eca070605d07f/pydantic_core-2.23.4-cp312-none-win_amd64.whl", hash = "sha256:97df63000f4fea395b2824da80e169731088656d1818a11b95f3b173747b6cd9", size = 1917992 }, { url = "https://files.pythonhosted.org/packages/ad/ef/16ee2df472bf0e419b6bc68c05bf0145c49247a1095e85cee1463c6a44a1/pydantic_core-2.23.4-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:7530e201d10d7d14abce4fb54cfe5b94a0aefc87da539d0346a484ead376c3cc", size = 1856143 }, { url = "https://files.pythonhosted.org/packages/da/fa/bc3dbb83605669a34a93308e297ab22be82dfb9dcf88c6cf4b4f264e0a42/pydantic_core-2.23.4-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:df933278128ea1cd77772673c73954e53a1c95a4fdf41eef97c2b779271bd0bd", size = 1770063 }, { url = "https://files.pythonhosted.org/packages/4e/48/e813f3bbd257a712303ebdf55c8dc46f9589ec74b384c9f652597df3288d/pydantic_core-2.23.4-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0cb3da3fd1b6a5d0279a01877713dbda118a2a4fc6f0d821a57da2e464793f05", size = 1790013 }, { url = "https://files.pythonhosted.org/packages/b4/e0/56eda3a37929a1d297fcab1966db8c339023bcca0b64c5a84896db3fcc5c/pydantic_core-2.23.4-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:42c6dcb030aefb668a2b7009c85b27f90e51e6a3b4d5c9bc4c57631292015b0d", size = 1801077 }, { url = "https://files.pythonhosted.org/packages/04/be/5e49376769bfbf82486da6c5c1683b891809365c20d7c7e52792ce4c71f3/pydantic_core-2.23.4-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:696dd8d674d6ce621ab9d45b205df149399e4bb9aa34102c970b721554828510", size = 1996782 }, { url = "https://files.pythonhosted.org/packages/bc/24/e3ee6c04f1d58cc15f37bcc62f32c7478ff55142b7b3e6d42ea374ea427c/pydantic_core-2.23.4-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2971bb5ffe72cc0f555c13e19b23c85b654dd2a8f7ab493c262071377bfce9f6", size = 2661375 }, { url = "https://files.pythonhosted.org/packages/c1/f8/11a9006de4e89d016b8de74ebb1db727dc100608bb1e6bbe9d56a3cbbcce/pydantic_core-2.23.4-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8394d940e5d400d04cad4f75c0598665cbb81aecefaca82ca85bd28264af7f9b", size = 2071635 }, { url = "https://files.pythonhosted.org/packages/7c/45/bdce5779b59f468bdf262a5bc9eecbae87f271c51aef628d8c073b4b4b4c/pydantic_core-2.23.4-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:0dff76e0602ca7d4cdaacc1ac4c005e0ce0dcfe095d5b5259163a80d3a10d327", size = 1916994 }, { url = "https://files.pythonhosted.org/packages/d8/fa/c648308fe711ee1f88192cad6026ab4f925396d1293e8356de7e55be89b5/pydantic_core-2.23.4-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:7d32706badfe136888bdea71c0def994644e09fff0bfe47441deaed8e96fdbc6", size = 1968877 }, { url = "https://files.pythonhosted.org/packages/16/16/b805c74b35607d24d37103007f899abc4880923b04929547ae68d478b7f4/pydantic_core-2.23.4-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:ed541d70698978a20eb63d8c5d72f2cc6d7079d9d90f6b50bad07826f1320f5f", size = 2116814 }, { url = "https://files.pythonhosted.org/packages/d1/58/5305e723d9fcdf1c5a655e6a4cc2a07128bf644ff4b1d98daf7a9dbf57da/pydantic_core-2.23.4-cp313-none-win32.whl", hash = "sha256:3d5639516376dce1940ea36edf408c554475369f5da2abd45d44621cb616f769", size = 1738360 }, { url = "https://files.pythonhosted.org/packages/a5/ae/e14b0ff8b3f48e02394d8acd911376b7b66e164535687ef7dc24ea03072f/pydantic_core-2.23.4-cp313-none-win_amd64.whl", hash = "sha256:5a1504ad17ba4210df3a045132a7baeeba5a200e930f57512ee02909fc5c4cb5", size = 1919411 }, { url = "https://files.pythonhosted.org/packages/7a/04/2580b2deaae37b3e30fc30c54298be938b973990b23612d6b61c7bdd01c7/pydantic_core-2.23.4-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:a4fa4fc04dff799089689f4fd502ce7d59de529fc2f40a2c8836886c03e0175a", size = 1868200 }, { url = "https://files.pythonhosted.org/packages/39/6e/e311bd0751505350f0cdcee3077841eb1f9253c5a1ddbad048cd9fbf7c6e/pydantic_core-2.23.4-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:0a7df63886be5e270da67e0966cf4afbae86069501d35c8c1b3b6c168f42cb36", size = 1749316 }, { url = "https://files.pythonhosted.org/packages/d0/b4/95b5eb47c6dc8692508c3ca04a1f8d6f0884c9dacb34cf3357595cbe73be/pydantic_core-2.23.4-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dcedcd19a557e182628afa1d553c3895a9f825b936415d0dbd3cd0bbcfd29b4b", size = 1800880 }, { url = "https://files.pythonhosted.org/packages/da/79/41c4f817acd7f42d94cd1e16526c062a7b089f66faed4bd30852314d9a66/pydantic_core-2.23.4-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:5f54b118ce5de9ac21c363d9b3caa6c800341e8c47a508787e5868c6b79c9323", size = 1807077 }, { url = "https://files.pythonhosted.org/packages/fb/53/d13d1eb0a97d5c06cf7a225935d471e9c241afd389a333f40c703f214973/pydantic_core-2.23.4-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:86d2f57d3e1379a9525c5ab067b27dbb8a0642fb5d454e17a9ac434f9ce523e3", size = 2002859 }, { url = "https://files.pythonhosted.org/packages/53/7d/6b8a1eff453774b46cac8c849e99455b27167971a003212f668e94bc4c9c/pydantic_core-2.23.4-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:de6d1d1b9e5101508cb37ab0d972357cac5235f5c6533d1071964c47139257df", size = 2661437 }, { url = "https://files.pythonhosted.org/packages/6c/ea/8820f57f0b46e6148ee42d8216b15e8fe3b360944284bbc705bf34fac888/pydantic_core-2.23.4-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1278e0d324f6908e872730c9102b0112477a7f7cf88b308e4fc36ce1bdb6d58c", size = 2054404 }, { url = "https://files.pythonhosted.org/packages/0f/36/d4ae869e473c3c7868e1cd1e2a1b9e13bce5cd1a7d287f6ac755a0b1575e/pydantic_core-2.23.4-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:9a6b5099eeec78827553827f4c6b8615978bb4b6a88e5d9b93eddf8bb6790f55", size = 1921680 }, { url = "https://files.pythonhosted.org/packages/0d/f8/eed5c65b80c4ac4494117e2101973b45fc655774ef647d17dde40a70f7d2/pydantic_core-2.23.4-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:e55541f756f9b3ee346b840103f32779c695a19826a4c442b7954550a0972040", size = 1966093 }, { url = "https://files.pythonhosted.org/packages/e8/c8/1d42ce51d65e571ab53d466cae83434325a126811df7ce4861d9d97bee4b/pydantic_core-2.23.4-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:a5c7ba8ffb6d6f8f2ab08743be203654bb1aaa8c9dcb09f82ddd34eadb695605", size = 2111437 }, { url = "https://files.pythonhosted.org/packages/aa/c9/7fea9d13383c2ec6865919e09cffe44ab77e911eb281b53a4deaafd4c8e8/pydantic_core-2.23.4-cp39-none-win32.whl", hash = "sha256:37b0fe330e4a58d3c58b24d91d1eb102aeec675a3db4c292ec3928ecd892a9a6", size = 1735049 }, { url = "https://files.pythonhosted.org/packages/98/95/dd7045c4caa2b73d0bf3b989d66b23cfbb7a0ef14ce99db15677a000a953/pydantic_core-2.23.4-cp39-none-win_amd64.whl", hash = "sha256:1498bec4c05c9c787bde9125cfdcc63a41004ff167f495063191b863399b1a29", size = 1920180 }, { url = "https://files.pythonhosted.org/packages/13/a9/5d582eb3204464284611f636b55c0a7410d748ff338756323cb1ce721b96/pydantic_core-2.23.4-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:f455ee30a9d61d3e1a15abd5068827773d6e4dc513e795f380cdd59932c782d5", size = 1857135 }, { url = "https://files.pythonhosted.org/packages/2c/57/faf36290933fe16717f97829eabfb1868182ac495f99cf0eda9f59687c9d/pydantic_core-2.23.4-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:1e90d2e3bd2c3863d48525d297cd143fe541be8bbf6f579504b9712cb6b643ec", size = 1740583 }, { url = "https://files.pythonhosted.org/packages/91/7c/d99e3513dc191c4fec363aef1bf4c8af9125d8fa53af7cb97e8babef4e40/pydantic_core-2.23.4-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2e203fdf807ac7e12ab59ca2bfcabb38c7cf0b33c41efeb00f8e5da1d86af480", size = 1793637 }, { url = "https://files.pythonhosted.org/packages/29/18/812222b6d18c2d13eebbb0f7cdc170a408d9ced65794fdb86147c77e1982/pydantic_core-2.23.4-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e08277a400de01bc72436a0ccd02bdf596631411f592ad985dcee21445bd0068", size = 1941963 }, { url = "https://files.pythonhosted.org/packages/0f/36/c1f3642ac3f05e6bb4aec3ffc399fa3f84895d259cf5f0ce3054b7735c29/pydantic_core-2.23.4-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:f220b0eea5965dec25480b6333c788fb72ce5f9129e8759ef876a1d805d00801", size = 1915332 }, { url = "https://files.pythonhosted.org/packages/f7/ca/9c0854829311fb446020ebb540ee22509731abad886d2859c855dd29b904/pydantic_core-2.23.4-pp310-pypy310_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:d06b0c8da4f16d1d1e352134427cb194a0a6e19ad5db9161bf32b2113409e728", size = 1957926 }, { url = "https://files.pythonhosted.org/packages/c0/1c/7836b67c42d0cd4441fcd9fafbf6a027ad4b79b6559f80cf11f89fd83648/pydantic_core-2.23.4-pp310-pypy310_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:ba1a0996f6c2773bd83e63f18914c1de3c9dd26d55f4ac302a7efe93fb8e7433", size = 2100342 }, { url = "https://files.pythonhosted.org/packages/a9/f9/b6bcaf874f410564a78908739c80861a171788ef4d4f76f5009656672dfe/pydantic_core-2.23.4-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:9a5bce9d23aac8f0cf0836ecfc033896aa8443b501c58d0602dbfd5bd5b37753", size = 1920344 }, { url = "https://files.pythonhosted.org/packages/32/fd/ac9cdfaaa7cf2d32590b807d900612b39acb25e5527c3c7e482f0553025b/pydantic_core-2.23.4-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:78ddaaa81421a29574a682b3179d4cf9e6d405a09b99d93ddcf7e5239c742e21", size = 1857850 }, { url = "https://files.pythonhosted.org/packages/08/fe/038f4b2bcae325ea643c8ad353191187a4c92a9c3b913b139289a6f2ef04/pydantic_core-2.23.4-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:883a91b5dd7d26492ff2f04f40fbb652de40fcc0afe07e8129e8ae779c2110eb", size = 1740265 }, { url = "https://files.pythonhosted.org/packages/51/14/b215c9c3cbd1edaaea23014d4b3304260823f712d3fdee52549b19b25d62/pydantic_core-2.23.4-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:88ad334a15b32a791ea935af224b9de1bf99bcd62fabf745d5f3442199d86d59", size = 1793912 }, { url = "https://files.pythonhosted.org/packages/62/de/2c3ad79b63ba564878cbce325be725929ba50089cd5156f89ea5155cb9b3/pydantic_core-2.23.4-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:233710f069d251feb12a56da21e14cca67994eab08362207785cf8c598e74577", size = 1942870 }, { url = "https://files.pythonhosted.org/packages/cb/55/c222af19e4644c741b3f3fe4fd8bbb6b4cdca87d8a49258b61cf7826b19e/pydantic_core-2.23.4-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:19442362866a753485ba5e4be408964644dd6a09123d9416c54cd49171f50744", size = 1915610 }, { url = "https://files.pythonhosted.org/packages/c4/7a/9a8760692a6f76bb54bcd43f245ff3d8b603db695899bbc624099c00af80/pydantic_core-2.23.4-pp39-pypy39_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:624e278a7d29b6445e4e813af92af37820fafb6dcc55c012c834f9e26f9aaaef", size = 1958403 }, { url = "https://files.pythonhosted.org/packages/4c/91/9b03166feb914bb5698e2f6499e07c2617e2eebf69f9374d0358d7eb2009/pydantic_core-2.23.4-pp39-pypy39_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:f5ef8f42bec47f21d07668a043f077d507e5bf4e668d5c6dfe6aaba89de1a5b8", size = 2101154 }, { url = "https://files.pythonhosted.org/packages/1d/d9/1d7ecb98318da4cb96986daaf0e20d66f1651d0aeb9e2d4435b916ce031d/pydantic_core-2.23.4-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:aea443fffa9fbe3af1a9ba721a87f926fe548d32cab71d188a6ede77d0ff244e", size = 1920855 }, ] [[package]] name = "pydocstyle" version = "6.3.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "snowballstemmer" }, ] sdist = { url = "https://files.pythonhosted.org/packages/e9/5c/d5385ca59fd065e3c6a5fe19f9bc9d5ea7f2509fa8c9c22fb6b2031dd953/pydocstyle-6.3.0.tar.gz", hash = "sha256:7ce43f0c0ac87b07494eb9c0b462c0b73e6ff276807f204d6b53edc72b7e44e1", size = 36796 } wheels = [ { url = "https://files.pythonhosted.org/packages/36/ea/99ddefac41971acad68f14114f38261c1f27dac0b3ec529824ebc739bdaa/pydocstyle-6.3.0-py3-none-any.whl", hash = "sha256:118762d452a49d6b05e194ef344a55822987a462831ade91ec5c06fd2169d019", size = 38038 }, ] [[package]] name = "pyflakes" version = "3.2.0" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/57/f9/669d8c9c86613c9d568757c7f5824bd3197d7b1c6c27553bc5618a27cce2/pyflakes-3.2.0.tar.gz", hash = "sha256:1c61603ff154621fb2a9172037d84dca3500def8c8b630657d1701f026f8af3f", size = 63788 } wheels = [ { url = "https://files.pythonhosted.org/packages/d4/d7/f1b7db88d8e4417c5d47adad627a93547f44bdc9028372dbd2313f34a855/pyflakes-3.2.0-py2.py3-none-any.whl", hash = "sha256:84b5be138a2dfbb40689ca07e2152deb896a65c3a3e24c251c5c62489568074a", size = 62725 }, ] [[package]] name = "pygments" version = "2.19.1" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/7c/2d/c3338d48ea6cc0feb8446d8e6937e1408088a72a39937982cc6111d17f84/pygments-2.19.1.tar.gz", hash = "sha256:61c16d2a8576dc0649d9f39e089b5f02bcd27fba10d8fb4dcc28173f7a45151f", size = 4968581 } wheels = [ { url = "https://files.pythonhosted.org/packages/8a/0b/9fcc47d19c48b59121088dd6da2488a49d5f72dacf8262e2790a1d2c7d15/pygments-2.19.1-py3-none-any.whl", hash = "sha256:9ea1544ad55cecf4b8242fab6dd35a93bbce657034b0611ee383099054ab6d8c", size = 1225293 }, ] [[package]] name = "pylama" version = "8.4.1" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "mccabe" }, { name = "pycodestyle" }, { name = "pydocstyle" }, { name = "pyflakes" }, ] sdist = { url = "https://files.pythonhosted.org/packages/bf/4f/b6e14fa7fcc805bdfc970c2505535722bcfac7d2a2ad4da826f4865dc0ef/pylama-8.4.1.tar.gz", hash = "sha256:2d4f7aecfb5b7466216d48610c7d6bad1c3990c29cdd392ad08259b161e486f6", size = 33616 } wheels = [ { url = "https://files.pythonhosted.org/packages/4d/3c/11be5c276f593f70d858db28e913449af76f07a1fb60612ef4131edc4527/pylama-8.4.1-py3-none-any.whl", hash = "sha256:5bbdbf5b620aba7206d688ed9fc917ecd3d73e15ec1a89647037a09fa3a86e60", size = 33151 }, ] [[package]] name = "pymdown-extensions" version = "10.4" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "markdown" }, { name = "pyyaml" }, ] sdist = { url = "https://files.pythonhosted.org/packages/85/71/5f48080bde77b07ca1eba6d7cb5c5598ac6c8f2a399846159b3c8b45e171/pymdown_extensions-10.4.tar.gz", hash = "sha256:bc46f11749ecd4d6b71cf62396104b4a200bad3498cb0f5dad1b8502fe461a35", size = 785151 } wheels = [ { url = "https://files.pythonhosted.org/packages/98/2d/2929de81618c7213176899dd6372d6ec9c8f24337841dd74634fb69864ae/pymdown_extensions-10.4-py3-none-any.whl", hash = "sha256:cfc28d6a09d19448bcbf8eee3ce098c7d17ff99f7bd3069db4819af181212037", size = 240838 }, ] [[package]] name = "pytest" version = "8.3.4" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "colorama", marker = "sys_platform == 'win32'" }, { name = "exceptiongroup", marker = "python_full_version < '3.11'" }, { name = "iniconfig" }, { name = "packaging" }, { name = "pluggy" }, { name = "tomli", marker = "python_full_version < '3.11'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/05/35/30e0d83068951d90a01852cb1cef56e5d8a09d20c7f511634cc2f7e0372a/pytest-8.3.4.tar.gz", hash = "sha256:965370d062bce11e73868e0335abac31b4d3de0e82f4007408d242b4f8610761", size = 1445919 } wheels = [ { url = "https://files.pythonhosted.org/packages/11/92/76a1c94d3afee238333bc0a42b82935dd8f9cf8ce9e336ff87ee14d9e1cf/pytest-8.3.4-py3-none-any.whl", hash = "sha256:50e16d954148559c9a74109af1eaf0c945ba2d8f30f0a3d3335edde19788b6f6", size = 343083 }, ] [[package]] name = "pytest-benchmark" version = "5.1.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "py-cpuinfo" }, { name = "pytest" }, ] sdist = { url = "https://files.pythonhosted.org/packages/39/d0/a8bd08d641b393db3be3819b03e2d9bb8760ca8479080a26a5f6e540e99c/pytest-benchmark-5.1.0.tar.gz", hash = "sha256:9ea661cdc292e8231f7cd4c10b0319e56a2118e2c09d9f50e1b3d150d2aca105", size = 337810 } wheels = [ { url = "https://files.pythonhosted.org/packages/9e/d6/b41653199ea09d5969d4e385df9bbfd9a100f28ca7e824ce7c0a016e3053/pytest_benchmark-5.1.0-py3-none-any.whl", hash = "sha256:922de2dfa3033c227c96da942d1878191afa135a29485fb942e85dff1c592c89", size = 44259 }, ] [[package]] name = "pytest-mock" version = "3.14.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "pytest" }, ] sdist = { url = "https://files.pythonhosted.org/packages/c6/90/a955c3ab35ccd41ad4de556596fa86685bf4fc5ffcc62d22d856cfd4e29a/pytest-mock-3.14.0.tar.gz", hash = "sha256:2719255a1efeceadbc056d6bf3df3d1c5015530fb40cf347c0f9afac88410bd0", size = 32814 } wheels = [ { url = "https://files.pythonhosted.org/packages/f2/3b/b26f90f74e2986a82df6e7ac7e319b8ea7ccece1caec9f8ab6104dc70603/pytest_mock-3.14.0-py3-none-any.whl", hash = "sha256:0b72c38033392a5f4621342fe11e9219ac11ec9d375f8e2a0c164539e0d70f6f", size = 9863 }, ] [[package]] name = "python-dateutil" version = "2.9.0.post0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "six" }, ] sdist = { url = "https://files.pythonhosted.org/packages/66/c0/0c8b6ad9f17a802ee498c46e004a0eb49bc148f2fd230864601a86dcf6db/python-dateutil-2.9.0.post0.tar.gz", hash = "sha256:37dd54208da7e1cd875388217d5e00ebd4179249f90fb72437e91a35459a0ad3", size = 342432 } wheels = [ { url = "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl", hash = "sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427", size = 229892 }, ] [[package]] name = "python-slugify" version = "8.0.4" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "text-unidecode" }, ] sdist = { url = "https://files.pythonhosted.org/packages/87/c7/5e1547c44e31da50a460df93af11a535ace568ef89d7a811069ead340c4a/python-slugify-8.0.4.tar.gz", hash = "sha256:59202371d1d05b54a9e7720c5e038f928f45daaffe41dd10822f3907b937c856", size = 10921 } wheels = [ { url = "https://files.pythonhosted.org/packages/a4/62/02da182e544a51a5c3ccf4b03ab79df279f9c60c5e82d5e8bec7ca26ac11/python_slugify-8.0.4-py2.py3-none-any.whl", hash = "sha256:276540b79961052b66b7d116620b36518847f52d5fd9e3a70164fc8c50faa6b8", size = 10051 }, ] [[package]] name = "pywin32" version = "308" source = { registry = "https://pypi.org/simple" } wheels = [ { url = "https://files.pythonhosted.org/packages/72/a6/3e9f2c474895c1bb61b11fa9640be00067b5c5b363c501ee9c3fa53aec01/pywin32-308-cp310-cp310-win32.whl", hash = "sha256:796ff4426437896550d2981b9c2ac0ffd75238ad9ea2d3bfa67a1abd546d262e", size = 5927028 }, { url = "https://files.pythonhosted.org/packages/d9/b4/84e2463422f869b4b718f79eb7530a4c1693e96b8a4e5e968de38be4d2ba/pywin32-308-cp310-cp310-win_amd64.whl", hash = "sha256:4fc888c59b3c0bef905ce7eb7e2106a07712015ea1c8234b703a088d46110e8e", size = 6558484 }, { url = "https://files.pythonhosted.org/packages/9f/8f/fb84ab789713f7c6feacaa08dad3ec8105b88ade8d1c4f0f0dfcaaa017d6/pywin32-308-cp310-cp310-win_arm64.whl", hash = "sha256:a5ab5381813b40f264fa3495b98af850098f814a25a63589a8e9eb12560f450c", size = 7971454 }, { url = "https://files.pythonhosted.org/packages/eb/e2/02652007469263fe1466e98439831d65d4ca80ea1a2df29abecedf7e47b7/pywin32-308-cp311-cp311-win32.whl", hash = "sha256:5d8c8015b24a7d6855b1550d8e660d8daa09983c80e5daf89a273e5c6fb5095a", size = 5928156 }, { url = "https://files.pythonhosted.org/packages/48/ef/f4fb45e2196bc7ffe09cad0542d9aff66b0e33f6c0954b43e49c33cad7bd/pywin32-308-cp311-cp311-win_amd64.whl", hash = "sha256:575621b90f0dc2695fec346b2d6302faebd4f0f45c05ea29404cefe35d89442b", size = 6559559 }, { url = "https://files.pythonhosted.org/packages/79/ef/68bb6aa865c5c9b11a35771329e95917b5559845bd75b65549407f9fc6b4/pywin32-308-cp311-cp311-win_arm64.whl", hash = "sha256:100a5442b7332070983c4cd03f2e906a5648a5104b8a7f50175f7906efd16bb6", size = 7972495 }, { url = "https://files.pythonhosted.org/packages/00/7c/d00d6bdd96de4344e06c4afbf218bc86b54436a94c01c71a8701f613aa56/pywin32-308-cp312-cp312-win32.whl", hash = "sha256:587f3e19696f4bf96fde9d8a57cec74a57021ad5f204c9e627e15c33ff568897", size = 5939729 }, { url = "https://files.pythonhosted.org/packages/21/27/0c8811fbc3ca188f93b5354e7c286eb91f80a53afa4e11007ef661afa746/pywin32-308-cp312-cp312-win_amd64.whl", hash = "sha256:00b3e11ef09ede56c6a43c71f2d31857cf7c54b0ab6e78ac659497abd2834f47", size = 6543015 }, { url = "https://files.pythonhosted.org/packages/9d/0f/d40f8373608caed2255781a3ad9a51d03a594a1248cd632d6a298daca693/pywin32-308-cp312-cp312-win_arm64.whl", hash = "sha256:9b4de86c8d909aed15b7011182c8cab38c8850de36e6afb1f0db22b8959e3091", size = 7976033 }, { url = "https://files.pythonhosted.org/packages/a9/a4/aa562d8935e3df5e49c161b427a3a2efad2ed4e9cf81c3de636f1fdddfd0/pywin32-308-cp313-cp313-win32.whl", hash = "sha256:1c44539a37a5b7b21d02ab34e6a4d314e0788f1690d65b48e9b0b89f31abbbed", size = 5938579 }, { url = "https://files.pythonhosted.org/packages/c7/50/b0efb8bb66210da67a53ab95fd7a98826a97ee21f1d22949863e6d588b22/pywin32-308-cp313-cp313-win_amd64.whl", hash = "sha256:fd380990e792eaf6827fcb7e187b2b4b1cede0585e3d0c9e84201ec27b9905e4", size = 6542056 }, { url = "https://files.pythonhosted.org/packages/26/df/2b63e3e4f2df0224f8aaf6d131f54fe4e8c96400eb9df563e2aae2e1a1f9/pywin32-308-cp313-cp313-win_arm64.whl", hash = "sha256:ef313c46d4c18dfb82a2431e3051ac8f112ccee1a34f29c263c583c568db63cd", size = 7974986 }, { url = "https://files.pythonhosted.org/packages/a8/41/ead05a7657ffdbb1edabb954ab80825c4f87a3de0285d59f8290457f9016/pywin32-308-cp39-cp39-win32.whl", hash = "sha256:7873ca4dc60ab3287919881a7d4f88baee4a6e639aa6962de25a98ba6b193341", size = 5991824 }, { url = "https://files.pythonhosted.org/packages/e4/cd/0838c9a6063bff2e9bac2388ae36524c26c50288b5d7b6aebb6cdf8d375d/pywin32-308-cp39-cp39-win_amd64.whl", hash = "sha256:71b3322d949b4cc20776436a9c9ba0eeedcbc9c650daa536df63f0ff111bb920", size = 6640327 }, ] [[package]] name = "pywin32-ctypes" version = "0.2.3" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/85/9f/01a1a99704853cb63f253eea009390c88e7131c67e66a0a02099a8c917cb/pywin32-ctypes-0.2.3.tar.gz", hash = "sha256:d162dc04946d704503b2edc4d55f3dba5c1d539ead017afa00142c38b9885755", size = 29471 } wheels = [ { url = "https://files.pythonhosted.org/packages/de/3d/8161f7711c017e01ac9f008dfddd9410dff3674334c233bde66e7ba65bbf/pywin32_ctypes-0.2.3-py3-none-any.whl", hash = "sha256:8a1513379d709975552d202d942d9837758905c8d01eb82b8bcc30918929e7b8", size = 30756 }, ] [[package]] name = "pyyaml" version = "6.0.2" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/54/ed/79a089b6be93607fa5cdaedf301d7dfb23af5f25c398d5ead2525b063e17/pyyaml-6.0.2.tar.gz", hash = "sha256:d584d9ec91ad65861cc08d42e834324ef890a082e591037abe114850ff7bbc3e", size = 130631 } wheels = [ { url = "https://files.pythonhosted.org/packages/9b/95/a3fac87cb7158e231b5a6012e438c647e1a87f09f8e0d123acec8ab8bf71/PyYAML-6.0.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:0a9a2848a5b7feac301353437eb7d5957887edbf81d56e903999a75a3d743086", size = 184199 }, { url = "https://files.pythonhosted.org/packages/c7/7a/68bd47624dab8fd4afbfd3c48e3b79efe09098ae941de5b58abcbadff5cb/PyYAML-6.0.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:29717114e51c84ddfba879543fb232a6ed60086602313ca38cce623c1d62cfbf", size = 171758 }, { url = "https://files.pythonhosted.org/packages/49/ee/14c54df452143b9ee9f0f29074d7ca5516a36edb0b4cc40c3f280131656f/PyYAML-6.0.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8824b5a04a04a047e72eea5cec3bc266db09e35de6bdfe34c9436ac5ee27d237", size = 718463 }, { url = "https://files.pythonhosted.org/packages/4d/61/de363a97476e766574650d742205be468921a7b532aa2499fcd886b62530/PyYAML-6.0.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7c36280e6fb8385e520936c3cb3b8042851904eba0e58d277dca80a5cfed590b", size = 719280 }, { url = "https://files.pythonhosted.org/packages/6b/4e/1523cb902fd98355e2e9ea5e5eb237cbc5f3ad5f3075fa65087aa0ecb669/PyYAML-6.0.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ec031d5d2feb36d1d1a24380e4db6d43695f3748343d99434e6f5f9156aaa2ed", size = 751239 }, { url = "https://files.pythonhosted.org/packages/b7/33/5504b3a9a4464893c32f118a9cc045190a91637b119a9c881da1cf6b7a72/PyYAML-6.0.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:936d68689298c36b53b29f23c6dbb74de12b4ac12ca6cfe0e047bedceea56180", size = 695802 }, { url = "https://files.pythonhosted.org/packages/5c/20/8347dcabd41ef3a3cdc4f7b7a2aff3d06598c8779faa189cdbf878b626a4/PyYAML-6.0.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:23502f431948090f597378482b4812b0caae32c22213aecf3b55325e049a6c68", size = 720527 }, { url = "https://files.pythonhosted.org/packages/be/aa/5afe99233fb360d0ff37377145a949ae258aaab831bde4792b32650a4378/PyYAML-6.0.2-cp310-cp310-win32.whl", hash = "sha256:2e99c6826ffa974fe6e27cdb5ed0021786b03fc98e5ee3c5bfe1fd5015f42b99", size = 144052 }, { url = "https://files.pythonhosted.org/packages/b5/84/0fa4b06f6d6c958d207620fc60005e241ecedceee58931bb20138e1e5776/PyYAML-6.0.2-cp310-cp310-win_amd64.whl", hash = "sha256:a4d3091415f010369ae4ed1fc6b79def9416358877534caf6a0fdd2146c87a3e", size = 161774 }, { url = "https://files.pythonhosted.org/packages/f8/aa/7af4e81f7acba21a4c6be026da38fd2b872ca46226673c89a758ebdc4fd2/PyYAML-6.0.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:cc1c1159b3d456576af7a3e4d1ba7e6924cb39de8f67111c735f6fc832082774", size = 184612 }, { url = "https://files.pythonhosted.org/packages/8b/62/b9faa998fd185f65c1371643678e4d58254add437edb764a08c5a98fb986/PyYAML-6.0.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:1e2120ef853f59c7419231f3bf4e7021f1b936f6ebd222406c3b60212205d2ee", size = 172040 }, { url = "https://files.pythonhosted.org/packages/ad/0c/c804f5f922a9a6563bab712d8dcc70251e8af811fce4524d57c2c0fd49a4/PyYAML-6.0.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5d225db5a45f21e78dd9358e58a98702a0302f2659a3c6cd320564b75b86f47c", size = 736829 }, { url = "https://files.pythonhosted.org/packages/51/16/6af8d6a6b210c8e54f1406a6b9481febf9c64a3109c541567e35a49aa2e7/PyYAML-6.0.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5ac9328ec4831237bec75defaf839f7d4564be1e6b25ac710bd1a96321cc8317", size = 764167 }, { url = "https://files.pythonhosted.org/packages/75/e4/2c27590dfc9992f73aabbeb9241ae20220bd9452df27483b6e56d3975cc5/PyYAML-6.0.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3ad2a3decf9aaba3d29c8f537ac4b243e36bef957511b4766cb0057d32b0be85", size = 762952 }, { url = "https://files.pythonhosted.org/packages/9b/97/ecc1abf4a823f5ac61941a9c00fe501b02ac3ab0e373c3857f7d4b83e2b6/PyYAML-6.0.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:ff3824dc5261f50c9b0dfb3be22b4567a6f938ccce4587b38952d85fd9e9afe4", size = 735301 }, { url = "https://files.pythonhosted.org/packages/45/73/0f49dacd6e82c9430e46f4a027baa4ca205e8b0a9dce1397f44edc23559d/PyYAML-6.0.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:797b4f722ffa07cc8d62053e4cff1486fa6dc094105d13fea7b1de7d8bf71c9e", size = 756638 }, { url = "https://files.pythonhosted.org/packages/22/5f/956f0f9fc65223a58fbc14459bf34b4cc48dec52e00535c79b8db361aabd/PyYAML-6.0.2-cp311-cp311-win32.whl", hash = "sha256:11d8f3dd2b9c1207dcaf2ee0bbbfd5991f571186ec9cc78427ba5bd32afae4b5", size = 143850 }, { url = "https://files.pythonhosted.org/packages/ed/23/8da0bbe2ab9dcdd11f4f4557ccaf95c10b9811b13ecced089d43ce59c3c8/PyYAML-6.0.2-cp311-cp311-win_amd64.whl", hash = "sha256:e10ce637b18caea04431ce14fabcf5c64a1c61ec9c56b071a4b7ca131ca52d44", size = 161980 }, { url = "https://files.pythonhosted.org/packages/86/0c/c581167fc46d6d6d7ddcfb8c843a4de25bdd27e4466938109ca68492292c/PyYAML-6.0.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:c70c95198c015b85feafc136515252a261a84561b7b1d51e3384e0655ddf25ab", size = 183873 }, { url = "https://files.pythonhosted.org/packages/a8/0c/38374f5bb272c051e2a69281d71cba6fdb983413e6758b84482905e29a5d/PyYAML-6.0.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:ce826d6ef20b1bc864f0a68340c8b3287705cae2f8b4b1d932177dcc76721725", size = 173302 }, { url = "https://files.pythonhosted.org/packages/c3/93/9916574aa8c00aa06bbac729972eb1071d002b8e158bd0e83a3b9a20a1f7/PyYAML-6.0.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1f71ea527786de97d1a0cc0eacd1defc0985dcf6b3f17bb77dcfc8c34bec4dc5", size = 739154 }, { url = "https://files.pythonhosted.org/packages/95/0f/b8938f1cbd09739c6da569d172531567dbcc9789e0029aa070856f123984/PyYAML-6.0.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9b22676e8097e9e22e36d6b7bda33190d0d400f345f23d4065d48f4ca7ae0425", size = 766223 }, { url = "https://files.pythonhosted.org/packages/b9/2b/614b4752f2e127db5cc206abc23a8c19678e92b23c3db30fc86ab731d3bd/PyYAML-6.0.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:80bab7bfc629882493af4aa31a4cfa43a4c57c83813253626916b8c7ada83476", size = 767542 }, { url = "https://files.pythonhosted.org/packages/d4/00/dd137d5bcc7efea1836d6264f049359861cf548469d18da90cd8216cf05f/PyYAML-6.0.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:0833f8694549e586547b576dcfaba4a6b55b9e96098b36cdc7ebefe667dfed48", size = 731164 }, { url = "https://files.pythonhosted.org/packages/c9/1f/4f998c900485e5c0ef43838363ba4a9723ac0ad73a9dc42068b12aaba4e4/PyYAML-6.0.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8b9c7197f7cb2738065c481a0461e50ad02f18c78cd75775628afb4d7137fb3b", size = 756611 }, { url = "https://files.pythonhosted.org/packages/df/d1/f5a275fdb252768b7a11ec63585bc38d0e87c9e05668a139fea92b80634c/PyYAML-6.0.2-cp312-cp312-win32.whl", hash = "sha256:ef6107725bd54b262d6dedcc2af448a266975032bc85ef0172c5f059da6325b4", size = 140591 }, { url = "https://files.pythonhosted.org/packages/0c/e8/4f648c598b17c3d06e8753d7d13d57542b30d56e6c2dedf9c331ae56312e/PyYAML-6.0.2-cp312-cp312-win_amd64.whl", hash = "sha256:7e7401d0de89a9a855c839bc697c079a4af81cf878373abd7dc625847d25cbd8", size = 156338 }, { url = "https://files.pythonhosted.org/packages/ef/e3/3af305b830494fa85d95f6d95ef7fa73f2ee1cc8ef5b495c7c3269fb835f/PyYAML-6.0.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:efdca5630322a10774e8e98e1af481aad470dd62c3170801852d752aa7a783ba", size = 181309 }, { url = "https://files.pythonhosted.org/packages/45/9f/3b1c20a0b7a3200524eb0076cc027a970d320bd3a6592873c85c92a08731/PyYAML-6.0.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:50187695423ffe49e2deacb8cd10510bc361faac997de9efef88badc3bb9e2d1", size = 171679 }, { url = "https://files.pythonhosted.org/packages/7c/9a/337322f27005c33bcb656c655fa78325b730324c78620e8328ae28b64d0c/PyYAML-6.0.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0ffe8360bab4910ef1b9e87fb812d8bc0a308b0d0eef8c8f44e0254ab3b07133", size = 733428 }, { url = "https://files.pythonhosted.org/packages/a3/69/864fbe19e6c18ea3cc196cbe5d392175b4cf3d5d0ac1403ec3f2d237ebb5/PyYAML-6.0.2-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:17e311b6c678207928d649faa7cb0d7b4c26a0ba73d41e99c4fff6b6c3276484", size = 763361 }, { url = "https://files.pythonhosted.org/packages/04/24/b7721e4845c2f162d26f50521b825fb061bc0a5afcf9a386840f23ea19fa/PyYAML-6.0.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:70b189594dbe54f75ab3a1acec5f1e3faa7e8cf2f1e08d9b561cb41b845f69d5", size = 759523 }, { url = "https://files.pythonhosted.org/packages/2b/b2/e3234f59ba06559c6ff63c4e10baea10e5e7df868092bf9ab40e5b9c56b6/PyYAML-6.0.2-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:41e4e3953a79407c794916fa277a82531dd93aad34e29c2a514c2c0c5fe971cc", size = 726660 }, { url = "https://files.pythonhosted.org/packages/fe/0f/25911a9f080464c59fab9027482f822b86bf0608957a5fcc6eaac85aa515/PyYAML-6.0.2-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:68ccc6023a3400877818152ad9a1033e3db8625d899c72eacb5a668902e4d652", size = 751597 }, { url = "https://files.pythonhosted.org/packages/14/0d/e2c3b43bbce3cf6bd97c840b46088a3031085179e596d4929729d8d68270/PyYAML-6.0.2-cp313-cp313-win32.whl", hash = "sha256:bc2fa7c6b47d6bc618dd7fb02ef6fdedb1090ec036abab80d4681424b84c1183", size = 140527 }, { url = "https://files.pythonhosted.org/packages/fa/de/02b54f42487e3d3c6efb3f89428677074ca7bf43aae402517bc7cca949f3/PyYAML-6.0.2-cp313-cp313-win_amd64.whl", hash = "sha256:8388ee1976c416731879ac16da0aff3f63b286ffdd57cdeb95f3f2e085687563", size = 156446 }, { url = "https://files.pythonhosted.org/packages/65/d8/b7a1db13636d7fb7d4ff431593c510c8b8fca920ade06ca8ef20015493c5/PyYAML-6.0.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:688ba32a1cffef67fd2e9398a2efebaea461578b0923624778664cc1c914db5d", size = 184777 }, { url = "https://files.pythonhosted.org/packages/0a/02/6ec546cd45143fdf9840b2c6be8d875116a64076218b61d68e12548e5839/PyYAML-6.0.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:a8786accb172bd8afb8be14490a16625cbc387036876ab6ba70912730faf8e1f", size = 172318 }, { url = "https://files.pythonhosted.org/packages/0e/9a/8cc68be846c972bda34f6c2a93abb644fb2476f4dcc924d52175786932c9/PyYAML-6.0.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d8e03406cac8513435335dbab54c0d385e4a49e4945d2909a581c83647ca0290", size = 720891 }, { url = "https://files.pythonhosted.org/packages/e9/6c/6e1b7f40181bc4805e2e07f4abc10a88ce4648e7e95ff1abe4ae4014a9b2/PyYAML-6.0.2-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f753120cb8181e736c57ef7636e83f31b9c0d1722c516f7e86cf15b7aa57ff12", size = 722614 }, { url = "https://files.pythonhosted.org/packages/3d/32/e7bd8535d22ea2874cef6a81021ba019474ace0d13a4819c2a4bce79bd6a/PyYAML-6.0.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3b1fdb9dc17f5a7677423d508ab4f243a726dea51fa5e70992e59a7411c89d19", size = 737360 }, { url = "https://files.pythonhosted.org/packages/d7/12/7322c1e30b9be969670b672573d45479edef72c9a0deac3bb2868f5d7469/PyYAML-6.0.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:0b69e4ce7a131fe56b7e4d770c67429700908fc0752af059838b1cfb41960e4e", size = 699006 }, { url = "https://files.pythonhosted.org/packages/82/72/04fcad41ca56491995076630c3ec1e834be241664c0c09a64c9a2589b507/PyYAML-6.0.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:a9f8c2e67970f13b16084e04f134610fd1d374bf477b17ec1599185cf611d725", size = 723577 }, { url = "https://files.pythonhosted.org/packages/ed/5e/46168b1f2757f1fcd442bc3029cd8767d88a98c9c05770d8b420948743bb/PyYAML-6.0.2-cp39-cp39-win32.whl", hash = "sha256:6395c297d42274772abc367baaa79683958044e5d3835486c16da75d2a694631", size = 144593 }, { url = "https://files.pythonhosted.org/packages/19/87/5124b1c1f2412bb95c59ec481eaf936cd32f0fe2a7b16b97b81c4c017a6a/PyYAML-6.0.2-cp39-cp39-win_amd64.whl", hash = "sha256:39693e1f8320ae4f43943590b49779ffb98acb81f788220ea932a6b6c51004d8", size = 162312 }, ] [[package]] name = "pyyaml-env-tag" version = "0.1" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "pyyaml" }, ] sdist = { url = "https://files.pythonhosted.org/packages/fb/8e/da1c6c58f751b70f8ceb1eb25bc25d524e8f14fe16edcce3f4e3ba08629c/pyyaml_env_tag-0.1.tar.gz", hash = "sha256:70092675bda14fdec33b31ba77e7543de9ddc88f2e5b99160396572d11525bdb", size = 5631 } wheels = [ { url = "https://files.pythonhosted.org/packages/5a/66/bbb1dd374f5c870f59c5bb1db0e18cbe7fa739415a24cbd95b2d1f5ae0c4/pyyaml_env_tag-0.1-py3-none-any.whl", hash = "sha256:af31106dec8a4d68c60207c1886031cbf839b68aa7abccdb19868200532c2069", size = 3911 }, ] [[package]] name = "pyzmq" version = "26.2.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "cffi", marker = "implementation_name == 'pypy'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/fd/05/bed626b9f7bb2322cdbbf7b4bd8f54b1b617b0d2ab2d3547d6e39428a48e/pyzmq-26.2.0.tar.gz", hash = "sha256:070672c258581c8e4f640b5159297580a9974b026043bd4ab0470be9ed324f1f", size = 271975 } wheels = [ { url = "https://files.pythonhosted.org/packages/1f/a8/9837c39aba390eb7d01924ace49d761c8dbe7bc2d6082346d00c8332e431/pyzmq-26.2.0-cp310-cp310-macosx_10_15_universal2.whl", hash = "sha256:ddf33d97d2f52d89f6e6e7ae66ee35a4d9ca6f36eda89c24591b0c40205a3629", size = 1340058 }, { url = "https://files.pythonhosted.org/packages/a2/1f/a006f2e8e4f7d41d464272012695da17fb95f33b54342612a6890da96ff6/pyzmq-26.2.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:dacd995031a01d16eec825bf30802fceb2c3791ef24bcce48fa98ce40918c27b", size = 1008818 }, { url = "https://files.pythonhosted.org/packages/b6/09/b51b6683fde5ca04593a57bbe81788b6b43114d8f8ee4e80afc991e14760/pyzmq-26.2.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:89289a5ee32ef6c439086184529ae060c741334b8970a6855ec0b6ad3ff28764", size = 673199 }, { url = "https://files.pythonhosted.org/packages/c9/78/486f3e2e824f3a645238332bf5a4c4b4477c3063033a27c1e4052358dee2/pyzmq-26.2.0-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5506f06d7dc6ecf1efacb4a013b1f05071bb24b76350832c96449f4a2d95091c", size = 911762 }, { url = "https://files.pythonhosted.org/packages/5e/3b/2eb1667c9b866f53e76ee8b0c301b0469745a23bd5a87b7ee3d5dd9eb6e5/pyzmq-26.2.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8ea039387c10202ce304af74def5021e9adc6297067f3441d348d2b633e8166a", size = 868773 }, { url = "https://files.pythonhosted.org/packages/16/29/ca99b4598a9dc7e468b5417eda91f372b595be1e3eec9b7cbe8e5d3584e8/pyzmq-26.2.0-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:a2224fa4a4c2ee872886ed00a571f5e967c85e078e8e8c2530a2fb01b3309b88", size = 868834 }, { url = "https://files.pythonhosted.org/packages/ad/e5/9efaeb1d2f4f8c50da04144f639b042bc52869d3a206d6bf672ab3522163/pyzmq-26.2.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:28ad5233e9c3b52d76196c696e362508959741e1a005fb8fa03b51aea156088f", size = 1202861 }, { url = "https://files.pythonhosted.org/packages/c3/62/c721b5608a8ac0a69bb83cbb7d07a56f3ff00b3991a138e44198a16f94c7/pyzmq-26.2.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:1c17211bc037c7d88e85ed8b7d8f7e52db6dc8eca5590d162717c654550f7282", size = 1515304 }, { url = "https://files.pythonhosted.org/packages/87/84/e8bd321aa99b72f48d4606fc5a0a920154125bd0a4608c67eab742dab087/pyzmq-26.2.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:b8f86dd868d41bea9a5f873ee13bf5551c94cf6bc51baebc6f85075971fe6eea", size = 1414712 }, { url = "https://files.pythonhosted.org/packages/cd/cd/420e3fd1ac6977b008b72e7ad2dae6350cc84d4c5027fc390b024e61738f/pyzmq-26.2.0-cp310-cp310-win32.whl", hash = "sha256:46a446c212e58456b23af260f3d9fb785054f3e3653dbf7279d8f2b5546b21c2", size = 578113 }, { url = "https://files.pythonhosted.org/packages/5c/57/73930d56ed45ae0cb4946f383f985c855c9b3d4063f26416998f07523c0e/pyzmq-26.2.0-cp310-cp310-win_amd64.whl", hash = "sha256:49d34ab71db5a9c292a7644ce74190b1dd5a3475612eefb1f8be1d6961441971", size = 641631 }, { url = "https://files.pythonhosted.org/packages/61/d2/ae6ac5c397f1ccad59031c64beaafce7a0d6182e0452cc48f1c9c87d2dd0/pyzmq-26.2.0-cp310-cp310-win_arm64.whl", hash = "sha256:bfa832bfa540e5b5c27dcf5de5d82ebc431b82c453a43d141afb1e5d2de025fa", size = 543528 }, { url = "https://files.pythonhosted.org/packages/12/20/de7442172f77f7c96299a0ac70e7d4fb78cd51eca67aa2cf552b66c14196/pyzmq-26.2.0-cp311-cp311-macosx_10_15_universal2.whl", hash = "sha256:8f7e66c7113c684c2b3f1c83cdd3376103ee0ce4c49ff80a648643e57fb22218", size = 1340639 }, { url = "https://files.pythonhosted.org/packages/98/4d/5000468bd64c7910190ed0a6c76a1ca59a68189ec1f007c451dc181a22f4/pyzmq-26.2.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:3a495b30fc91db2db25120df5847d9833af237546fd59170701acd816ccc01c4", size = 1008710 }, { url = "https://files.pythonhosted.org/packages/e1/bf/c67fd638c2f9fbbab8090a3ee779370b97c82b84cc12d0c498b285d7b2c0/pyzmq-26.2.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:77eb0968da535cba0470a5165468b2cac7772cfb569977cff92e240f57e31bef", size = 673129 }, { url = "https://files.pythonhosted.org/packages/86/94/99085a3f492aa538161cbf27246e8886ff850e113e0c294a5b8245f13b52/pyzmq-26.2.0-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6ace4f71f1900a548f48407fc9be59c6ba9d9aaf658c2eea6cf2779e72f9f317", size = 910107 }, { url = "https://files.pythonhosted.org/packages/31/1d/346809e8a9b999646d03f21096428453465b1bca5cd5c64ecd048d9ecb01/pyzmq-26.2.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:92a78853d7280bffb93df0a4a6a2498cba10ee793cc8076ef797ef2f74d107cf", size = 867960 }, { url = "https://files.pythonhosted.org/packages/ab/68/6fb6ae5551846ad5beca295b7bca32bf0a7ce19f135cb30e55fa2314e6b6/pyzmq-26.2.0-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:689c5d781014956a4a6de61d74ba97b23547e431e9e7d64f27d4922ba96e9d6e", size = 869204 }, { url = "https://files.pythonhosted.org/packages/0f/f9/18417771dee223ccf0f48e29adf8b4e25ba6d0e8285e33bcbce078070bc3/pyzmq-26.2.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:0aca98bc423eb7d153214b2df397c6421ba6373d3397b26c057af3c904452e37", size = 1203351 }, { url = "https://files.pythonhosted.org/packages/e0/46/f13e67fe0d4f8a2315782cbad50493de6203ea0d744610faf4d5f5b16e90/pyzmq-26.2.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:1f3496d76b89d9429a656293744ceca4d2ac2a10ae59b84c1da9b5165f429ad3", size = 1514204 }, { url = "https://files.pythonhosted.org/packages/50/11/ddcf7343b7b7a226e0fc7b68cbf5a5bb56291fac07f5c3023bb4c319ebb4/pyzmq-26.2.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:5c2b3bfd4b9689919db068ac6c9911f3fcb231c39f7dd30e3138be94896d18e6", size = 1414339 }, { url = "https://files.pythonhosted.org/packages/01/14/1c18d7d5b7be2708f513f37c61bfadfa62161c10624f8733f1c8451b3509/pyzmq-26.2.0-cp311-cp311-win32.whl", hash = "sha256:eac5174677da084abf378739dbf4ad245661635f1600edd1221f150b165343f4", size = 576928 }, { url = "https://files.pythonhosted.org/packages/3b/1b/0a540edd75a41df14ec416a9a500b9fec66e554aac920d4c58fbd5756776/pyzmq-26.2.0-cp311-cp311-win_amd64.whl", hash = "sha256:5a509df7d0a83a4b178d0f937ef14286659225ef4e8812e05580776c70e155d5", size = 642317 }, { url = "https://files.pythonhosted.org/packages/98/77/1cbfec0358078a4c5add529d8a70892db1be900980cdb5dd0898b3d6ab9d/pyzmq-26.2.0-cp311-cp311-win_arm64.whl", hash = "sha256:c0e6091b157d48cbe37bd67233318dbb53e1e6327d6fc3bb284afd585d141003", size = 543834 }, { url = "https://files.pythonhosted.org/packages/28/2f/78a766c8913ad62b28581777ac4ede50c6d9f249d39c2963e279524a1bbe/pyzmq-26.2.0-cp312-cp312-macosx_10_15_universal2.whl", hash = "sha256:ded0fc7d90fe93ae0b18059930086c51e640cdd3baebdc783a695c77f123dcd9", size = 1343105 }, { url = "https://files.pythonhosted.org/packages/b7/9c/4b1e2d3d4065be715e007fe063ec7885978fad285f87eae1436e6c3201f4/pyzmq-26.2.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:17bf5a931c7f6618023cdacc7081f3f266aecb68ca692adac015c383a134ca52", size = 1008365 }, { url = "https://files.pythonhosted.org/packages/4f/ef/5a23ec689ff36d7625b38d121ef15abfc3631a9aecb417baf7a4245e4124/pyzmq-26.2.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:55cf66647e49d4621a7e20c8d13511ef1fe1efbbccf670811864452487007e08", size = 665923 }, { url = "https://files.pythonhosted.org/packages/ae/61/d436461a47437d63c6302c90724cf0981883ec57ceb6073873f32172d676/pyzmq-26.2.0-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4661c88db4a9e0f958c8abc2b97472e23061f0bc737f6f6179d7a27024e1faa5", size = 903400 }, { url = "https://files.pythonhosted.org/packages/47/42/fc6d35ecefe1739a819afaf6f8e686f7f02a4dd241c78972d316f403474c/pyzmq-26.2.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ea7f69de383cb47522c9c208aec6dd17697db7875a4674c4af3f8cfdac0bdeae", size = 860034 }, { url = "https://files.pythonhosted.org/packages/07/3b/44ea6266a6761e9eefaa37d98fabefa112328808ac41aa87b4bbb668af30/pyzmq-26.2.0-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:7f98f6dfa8b8ccaf39163ce872bddacca38f6a67289116c8937a02e30bbe9711", size = 860579 }, { url = "https://files.pythonhosted.org/packages/38/6f/4df2014ab553a6052b0e551b37da55166991510f9e1002c89cab7ce3b3f2/pyzmq-26.2.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:e3e0210287329272539eea617830a6a28161fbbd8a3271bf4150ae3e58c5d0e6", size = 1196246 }, { url = "https://files.pythonhosted.org/packages/38/9d/ee240fc0c9fe9817f0c9127a43238a3e28048795483c403cc10720ddef22/pyzmq-26.2.0-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:6b274e0762c33c7471f1a7471d1a2085b1a35eba5cdc48d2ae319f28b6fc4de3", size = 1507441 }, { url = "https://files.pythonhosted.org/packages/85/4f/01711edaa58d535eac4a26c294c617c9a01f09857c0ce191fd574d06f359/pyzmq-26.2.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:29c6a4635eef69d68a00321e12a7d2559fe2dfccfa8efae3ffb8e91cd0b36a8b", size = 1406498 }, { url = "https://files.pythonhosted.org/packages/07/18/907134c85c7152f679ed744e73e645b365f3ad571f38bdb62e36f347699a/pyzmq-26.2.0-cp312-cp312-win32.whl", hash = "sha256:989d842dc06dc59feea09e58c74ca3e1678c812a4a8a2a419046d711031f69c7", size = 575533 }, { url = "https://files.pythonhosted.org/packages/ce/2c/a6f4a20202a4d3c582ad93f95ee78d79bbdc26803495aec2912b17dbbb6c/pyzmq-26.2.0-cp312-cp312-win_amd64.whl", hash = "sha256:2a50625acdc7801bc6f74698c5c583a491c61d73c6b7ea4dee3901bb99adb27a", size = 637768 }, { url = "https://files.pythonhosted.org/packages/5f/0e/eb16ff731632d30554bf5af4dbba3ffcd04518219d82028aea4ae1b02ca5/pyzmq-26.2.0-cp312-cp312-win_arm64.whl", hash = "sha256:4d29ab8592b6ad12ebbf92ac2ed2bedcfd1cec192d8e559e2e099f648570e19b", size = 540675 }, { url = "https://files.pythonhosted.org/packages/04/a7/0f7e2f6c126fe6e62dbae0bc93b1bd3f1099cf7fea47a5468defebe3f39d/pyzmq-26.2.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:9dd8cd1aeb00775f527ec60022004d030ddc51d783d056e3e23e74e623e33726", size = 1006564 }, { url = "https://files.pythonhosted.org/packages/31/b6/a187165c852c5d49f826a690857684333a6a4a065af0a6015572d2284f6a/pyzmq-26.2.0-cp313-cp313-macosx_10_15_universal2.whl", hash = "sha256:28c812d9757fe8acecc910c9ac9dafd2ce968c00f9e619db09e9f8f54c3a68a3", size = 1340447 }, { url = "https://files.pythonhosted.org/packages/68/ba/f4280c58ff71f321602a6e24fd19879b7e79793fb8ab14027027c0fb58ef/pyzmq-26.2.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4d80b1dd99c1942f74ed608ddb38b181b87476c6a966a88a950c7dee118fdf50", size = 665485 }, { url = "https://files.pythonhosted.org/packages/77/b5/c987a5c53c7d8704216f29fc3d810b32f156bcea488a940e330e1bcbb88d/pyzmq-26.2.0-cp313-cp313-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8c997098cc65e3208eca09303630e84d42718620e83b733d0fd69543a9cab9cb", size = 903484 }, { url = "https://files.pythonhosted.org/packages/29/c9/07da157d2db18c72a7eccef8e684cefc155b712a88e3d479d930aa9eceba/pyzmq-26.2.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7ad1bc8d1b7a18497dda9600b12dc193c577beb391beae5cd2349184db40f187", size = 859981 }, { url = "https://files.pythonhosted.org/packages/43/09/e12501bd0b8394b7d02c41efd35c537a1988da67fc9c745cae9c6c776d31/pyzmq-26.2.0-cp313-cp313-manylinux_2_28_x86_64.whl", hash = "sha256:bea2acdd8ea4275e1278350ced63da0b166421928276c7c8e3f9729d7402a57b", size = 860334 }, { url = "https://files.pythonhosted.org/packages/eb/ff/f5ec1d455f8f7385cc0a8b2acd8c807d7fade875c14c44b85c1bddabae21/pyzmq-26.2.0-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:23f4aad749d13698f3f7b64aad34f5fc02d6f20f05999eebc96b89b01262fb18", size = 1196179 }, { url = "https://files.pythonhosted.org/packages/ec/8a/bb2ac43295b1950fe436a81fc5b298be0b96ac76fb029b514d3ed58f7b27/pyzmq-26.2.0-cp313-cp313-musllinux_1_1_i686.whl", hash = "sha256:a4f96f0d88accc3dbe4a9025f785ba830f968e21e3e2c6321ccdfc9aef755115", size = 1507668 }, { url = "https://files.pythonhosted.org/packages/a9/49/dbc284ebcfd2dca23f6349227ff1616a7ee2c4a35fe0a5d6c3deff2b4fed/pyzmq-26.2.0-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:ced65e5a985398827cc9276b93ef6dfabe0273c23de8c7931339d7e141c2818e", size = 1406539 }, { url = "https://files.pythonhosted.org/packages/00/68/093cdce3fe31e30a341d8e52a1ad86392e13c57970d722c1f62a1d1a54b6/pyzmq-26.2.0-cp313-cp313-win32.whl", hash = "sha256:31507f7b47cc1ead1f6e86927f8ebb196a0bab043f6345ce070f412a59bf87b5", size = 575567 }, { url = "https://files.pythonhosted.org/packages/92/ae/6cc4657148143412b5819b05e362ae7dd09fb9fe76e2a539dcff3d0386bc/pyzmq-26.2.0-cp313-cp313-win_amd64.whl", hash = "sha256:70fc7fcf0410d16ebdda9b26cbd8bf8d803d220a7f3522e060a69a9c87bf7bad", size = 637551 }, { url = "https://files.pythonhosted.org/packages/6c/67/fbff102e201688f97c8092e4c3445d1c1068c2f27bbd45a578df97ed5f94/pyzmq-26.2.0-cp313-cp313-win_arm64.whl", hash = "sha256:c3789bd5768ab5618ebf09cef6ec2b35fed88709b104351748a63045f0ff9797", size = 540378 }, { url = "https://files.pythonhosted.org/packages/3f/fe/2d998380b6e0122c6c4bdf9b6caf490831e5f5e2d08a203b5adff060c226/pyzmq-26.2.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:034da5fc55d9f8da09015d368f519478a52675e558c989bfcb5cf6d4e16a7d2a", size = 1007378 }, { url = "https://files.pythonhosted.org/packages/4a/f4/30d6e7157f12b3a0390bde94d6a8567cdb88846ed068a6e17238a4ccf600/pyzmq-26.2.0-cp313-cp313t-macosx_10_15_universal2.whl", hash = "sha256:c92d73464b886931308ccc45b2744e5968cbaade0b1d6aeb40d8ab537765f5bc", size = 1329532 }, { url = "https://files.pythonhosted.org/packages/82/86/3fe917870e15ee1c3ad48229a2a64458e36036e64b4afa9659045d82bfa8/pyzmq-26.2.0-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:794a4562dcb374f7dbbfb3f51d28fb40123b5a2abadee7b4091f93054909add5", size = 653242 }, { url = "https://files.pythonhosted.org/packages/50/2d/242e7e6ef6c8c19e6cb52d095834508cd581ffb925699fd3c640cdc758f1/pyzmq-26.2.0-cp313-cp313t-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:aee22939bb6075e7afededabad1a56a905da0b3c4e3e0c45e75810ebe3a52672", size = 888404 }, { url = "https://files.pythonhosted.org/packages/ac/11/7270566e1f31e4ea73c81ec821a4b1688fd551009a3d2bab11ec66cb1e8f/pyzmq-26.2.0-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2ae90ff9dad33a1cfe947d2c40cb9cb5e600d759ac4f0fd22616ce6540f72797", size = 845858 }, { url = "https://files.pythonhosted.org/packages/91/d5/72b38fbc69867795c8711bdd735312f9fef1e3d9204e2f63ab57085434b9/pyzmq-26.2.0-cp313-cp313t-manylinux_2_28_x86_64.whl", hash = "sha256:43a47408ac52647dfabbc66a25b05b6a61700b5165807e3fbd40063fcaf46386", size = 847375 }, { url = "https://files.pythonhosted.org/packages/dd/9a/10ed3c7f72b4c24e719c59359fbadd1a27556a28b36cdf1cd9e4fb7845d5/pyzmq-26.2.0-cp313-cp313t-musllinux_1_1_aarch64.whl", hash = "sha256:25bf2374a2a8433633c65ccb9553350d5e17e60c8eb4de4d92cc6bd60f01d306", size = 1183489 }, { url = "https://files.pythonhosted.org/packages/72/2d/8660892543fabf1fe41861efa222455811adac9f3c0818d6c3170a1153e3/pyzmq-26.2.0-cp313-cp313t-musllinux_1_1_i686.whl", hash = "sha256:007137c9ac9ad5ea21e6ad97d3489af654381324d5d3ba614c323f60dab8fae6", size = 1492932 }, { url = "https://files.pythonhosted.org/packages/7b/d6/32fd69744afb53995619bc5effa2a405ae0d343cd3e747d0fbc43fe894ee/pyzmq-26.2.0-cp313-cp313t-musllinux_1_1_x86_64.whl", hash = "sha256:470d4a4f6d48fb34e92d768b4e8a5cc3780db0d69107abf1cd7ff734b9766eb0", size = 1392485 }, { url = "https://files.pythonhosted.org/packages/ac/9e/ad5fbbe1bcc7a9d1e8c5f4f7de48f2c1dc481e151ef80cc1ce9a7fe67b55/pyzmq-26.2.0-cp39-cp39-macosx_10_15_universal2.whl", hash = "sha256:b1d464cb8d72bfc1a3adc53305a63a8e0cac6bc8c5a07e8ca190ab8d3faa43c2", size = 1341256 }, { url = "https://files.pythonhosted.org/packages/4c/d9/d7a8022108c214803a82b0b69d4885cee00933d21928f1f09dca371cf4bf/pyzmq-26.2.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:4da04c48873a6abdd71811c5e163bd656ee1b957971db7f35140a2d573f6949c", size = 1009385 }, { url = "https://files.pythonhosted.org/packages/ed/69/0529b59ac667ea8bfe8796ac71796b688fbb42ff78e06525dabfed3bc7ae/pyzmq-26.2.0-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:d049df610ac811dcffdc147153b414147428567fbbc8be43bb8885f04db39d98", size = 908009 }, { url = "https://files.pythonhosted.org/packages/6e/bd/3ff3e1172f12f55769793a3a334e956ec2886805ebfb2f64756b6b5c6a1a/pyzmq-26.2.0-cp39-cp39-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:05590cdbc6b902101d0e65d6a4780af14dc22914cc6ab995d99b85af45362cc9", size = 862078 }, { url = "https://files.pythonhosted.org/packages/c3/ec/ab13585c3a1f48e2874253844c47b194d56eb25c94718691349c646f336f/pyzmq-26.2.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c811cfcd6a9bf680236c40c6f617187515269ab2912f3d7e8c0174898e2519db", size = 673756 }, { url = "https://files.pythonhosted.org/packages/1e/be/febcd4b04dd50ee6d514dfbc33a3d5d9cb38ec9516e02bbfc929baa0f141/pyzmq-26.2.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:6835dd60355593de10350394242b5757fbbd88b25287314316f266e24c61d073", size = 1203684 }, { url = "https://files.pythonhosted.org/packages/16/28/304150e71afd2df3b82f52f66c0d8ab9ac6fe1f1ffdf92bad4c8cc91d557/pyzmq-26.2.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:bc6bee759a6bddea5db78d7dcd609397449cb2d2d6587f48f3ca613b19410cfc", size = 1515864 }, { url = "https://files.pythonhosted.org/packages/18/89/8d48d8cd505c12a1f5edee597cc32ffcedc65fd8d2603aebaaedc38a7041/pyzmq-26.2.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:c530e1eecd036ecc83c3407f77bb86feb79916d4a33d11394b8234f3bd35b940", size = 1415383 }, { url = "https://files.pythonhosted.org/packages/d4/7e/43a60c3b179f7da0cbc2b649bd2702fd6a39bff5f72aa38d6e1aeb00256d/pyzmq-26.2.0-cp39-cp39-win32.whl", hash = "sha256:367b4f689786fca726ef7a6c5ba606958b145b9340a5e4808132cc65759abd44", size = 578540 }, { url = "https://files.pythonhosted.org/packages/3a/55/8841dcd28f783ad06674c8fe8d7d72794b548d0bff8829aaafeb72e8b44d/pyzmq-26.2.0-cp39-cp39-win_amd64.whl", hash = "sha256:e6fa2e3e683f34aea77de8112f6483803c96a44fd726d7358b9888ae5bb394ec", size = 642147 }, { url = "https://files.pythonhosted.org/packages/b4/78/b3c31ccfcfcdd6ea50b6abc8f46a2a7aadb9c3d40531d1b908d834aaa12e/pyzmq-26.2.0-cp39-cp39-win_arm64.whl", hash = "sha256:7445be39143a8aa4faec43b076e06944b8f9d0701b669df4af200531b21e40bb", size = 543903 }, { url = "https://files.pythonhosted.org/packages/53/fb/36b2b2548286e9444e52fcd198760af99fd89102b5be50f0660fcfe902df/pyzmq-26.2.0-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:706e794564bec25819d21a41c31d4df2d48e1cc4b061e8d345d7fb4dd3e94072", size = 906955 }, { url = "https://files.pythonhosted.org/packages/77/8f/6ce54f8979a01656e894946db6299e2273fcee21c8e5fa57c6295ef11f57/pyzmq-26.2.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8b435f2753621cd36e7c1762156815e21c985c72b19135dac43a7f4f31d28dd1", size = 565701 }, { url = "https://files.pythonhosted.org/packages/ee/1c/bf8cd66730a866b16db8483286078892b7f6536f8c389fb46e4beba0a970/pyzmq-26.2.0-pp310-pypy310_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:160c7e0a5eb178011e72892f99f918c04a131f36056d10d9c1afb223fc952c2d", size = 794312 }, { url = "https://files.pythonhosted.org/packages/71/43/91fa4ff25bbfdc914ab6bafa0f03241d69370ef31a761d16bb859f346582/pyzmq-26.2.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2c4a71d5d6e7b28a47a394c0471b7e77a0661e2d651e7ae91e0cab0a587859ca", size = 752775 }, { url = "https://files.pythonhosted.org/packages/ec/d2/3b2ab40f455a256cb6672186bea95cd97b459ce4594050132d71e76f0d6f/pyzmq-26.2.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:90412f2db8c02a3864cbfc67db0e3dcdbda336acf1c469526d3e869394fe001c", size = 550762 }, { url = "https://files.pythonhosted.org/packages/6c/78/3096d72581365dfb0081ac9512a3b53672fa69854aa174d78636510c4db8/pyzmq-26.2.0-pp39-pypy39_pp73-macosx_10_15_x86_64.whl", hash = "sha256:cdeabcff45d1c219636ee2e54d852262e5c2e085d6cb476d938aee8d921356b3", size = 906945 }, { url = "https://files.pythonhosted.org/packages/da/f2/8054574d77c269c31d055d4daf3d8407adf61ea384a50c8d14b158551d09/pyzmq-26.2.0-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:35cffef589bcdc587d06f9149f8d5e9e8859920a071df5a2671de2213bef592a", size = 565698 }, { url = "https://files.pythonhosted.org/packages/77/21/c3ad93236d1d60eea10b67528f55e7db115a9d32e2bf163fcf601f85e9cc/pyzmq-26.2.0-pp39-pypy39_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:18c8dc3b7468d8b4bdf60ce9d7141897da103c7a4690157b32b60acb45e333e6", size = 794307 }, { url = "https://files.pythonhosted.org/packages/6a/49/e95b491724500fcb760178ce8db39b923429e328e57bcf9162e32c2c187c/pyzmq-26.2.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7133d0a1677aec369d67dd78520d3fa96dd7f3dcec99d66c1762870e5ea1a50a", size = 752769 }, { url = "https://files.pythonhosted.org/packages/9b/a9/50c9c06762b30792f71aaad8d1886748d39c4bffedc1171fbc6ad2b92d67/pyzmq-26.2.0-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:6a96179a24b14fa6428cbfc08641c779a53f8fcec43644030328f44034c7f1f4", size = 751338 }, { url = "https://files.pythonhosted.org/packages/ca/63/27e6142b4f67a442ee480986ca5b88edb01462dd2319843057683a5148bd/pyzmq-26.2.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:4f78c88905461a9203eac9faac157a2a0dbba84a0fd09fd29315db27be40af9f", size = 550757 }, ] [[package]] name = "referencing" version = "0.36.1" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "attrs" }, { name = "rpds-py" }, { name = "typing-extensions", marker = "python_full_version < '3.13'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/27/32/fd98246df7a0f309b58cae68b10b6b219ef2eb66747f00dfb34422687087/referencing-0.36.1.tar.gz", hash = "sha256:ca2e6492769e3602957e9b831b94211599d2aade9477f5d44110d2530cf9aade", size = 74661 } wheels = [ { url = "https://files.pythonhosted.org/packages/cc/fa/9f193ef0c9074b659009f06d7cbacc6f25b072044815bcf799b76533dbb8/referencing-0.36.1-py3-none-any.whl", hash = "sha256:363d9c65f080d0d70bc41c721dce3c7f3e77fc09f269cd5c8813da18069a6794", size = 26777 }, ] [[package]] name = "requests" version = "2.32.3" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "certifi" }, { name = "charset-normalizer" }, { name = "idna" }, { name = "urllib3" }, ] sdist = { url = "https://files.pythonhosted.org/packages/63/70/2bf7780ad2d390a8d301ad0b550f1581eadbd9a20f896afe06353c2a2913/requests-2.32.3.tar.gz", hash = "sha256:55365417734eb18255590a9ff9eb97e9e1da868d4ccd6402399eaf68af20a760", size = 131218 } wheels = [ { url = "https://files.pythonhosted.org/packages/f9/9b/335f9764261e915ed497fcdeb11df5dfd6f7bf257d4a6a2a686d80da4d54/requests-2.32.3-py3-none-any.whl", hash = "sha256:70761cfe03c773ceb22aa2f671b4757976145175cdfca038c02654d061d6dcc6", size = 64928 }, ] [[package]] name = "requirementslib" version = "3.0.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "distlib" }, { name = "pep517" }, { name = "pip" }, { name = "platformdirs" }, { name = "plette", extra = ["validation"] }, { name = "pydantic" }, { name = "requests" }, { name = "setuptools" }, { name = "tomlkit" }, ] sdist = { url = "https://files.pythonhosted.org/packages/7f/05/3b5b4d0aea645059f98d90ed45ce390c3955712b5c4c2cbe6c90d3333f09/requirementslib-3.0.0.tar.gz", hash = "sha256:28f8e0b1c38b34ae06de68ef115b03bbcdcdb99f9e9393333ff06ded443e3f24", size = 108130 } wheels = [ { url = "https://files.pythonhosted.org/packages/8a/6e/2d0c72c224f760d49e954f6c0eb5e4075b589c7e99e895ba0b250dc6e469/requirementslib-3.0.0-py2.py3-none-any.whl", hash = "sha256:67b42903d7c32f89c7047d1020c619d37cb515c475a4ae6f4e5683e1c56d7bf7", size = 96688 }, ] [[package]] name = "rich" version = "13.9.4" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "markdown-it-py" }, { name = "pygments" }, { name = "typing-extensions", marker = "python_full_version < '3.11'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/ab/3a/0316b28d0761c6734d6bc14e770d85506c986c85ffb239e688eeaab2c2bc/rich-13.9.4.tar.gz", hash = "sha256:439594978a49a09530cff7ebc4b5c7103ef57baf48d5ea3184f21d9a2befa098", size = 223149 } wheels = [ { url = "https://files.pythonhosted.org/packages/19/71/39c7c0d87f8d4e6c020a393182060eaefeeae6c01dab6a84ec346f2567df/rich-13.9.4-py3-none-any.whl", hash = "sha256:6049d5e6ec054bf2779ab3358186963bac2ea89175919d699e378b99738c2a90", size = 242424 }, ] [[package]] name = "rpds-py" version = "0.22.3" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/01/80/cce854d0921ff2f0a9fa831ba3ad3c65cee3a46711addf39a2af52df2cfd/rpds_py-0.22.3.tar.gz", hash = "sha256:e32fee8ab45d3c2db6da19a5323bc3362237c8b653c70194414b892fd06a080d", size = 26771 } wheels = [ { url = "https://files.pythonhosted.org/packages/42/2a/ead1d09e57449b99dcc190d8d2323e3a167421d8f8fdf0f217c6f6befe47/rpds_py-0.22.3-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:6c7b99ca52c2c1752b544e310101b98a659b720b21db00e65edca34483259967", size = 359514 }, { url = "https://files.pythonhosted.org/packages/8f/7e/1254f406b7793b586c68e217a6a24ec79040f85e030fff7e9049069284f4/rpds_py-0.22.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:be2eb3f2495ba669d2a985f9b426c1797b7d48d6963899276d22f23e33d47e37", size = 349031 }, { url = "https://files.pythonhosted.org/packages/aa/da/17c6a2c73730d426df53675ff9cc6653ac7a60b6438d03c18e1c822a576a/rpds_py-0.22.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:70eb60b3ae9245ddea20f8a4190bd79c705a22f8028aaf8bbdebe4716c3fab24", size = 381485 }, { url = "https://files.pythonhosted.org/packages/aa/13/2dbacd820466aa2a3c4b747afb18d71209523d353cf865bf8f4796c969ea/rpds_py-0.22.3-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:4041711832360a9b75cfb11b25a6a97c8fb49c07b8bd43d0d02b45d0b499a4ff", size = 386794 }, { url = "https://files.pythonhosted.org/packages/6d/62/96905d0a35ad4e4bc3c098b2f34b2e7266e211d08635baa690643d2227be/rpds_py-0.22.3-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:64607d4cbf1b7e3c3c8a14948b99345eda0e161b852e122c6bb71aab6d1d798c", size = 423523 }, { url = "https://files.pythonhosted.org/packages/eb/1b/d12770f2b6a9fc2c3ec0d810d7d440f6d465ccd8b7f16ae5385952c28b89/rpds_py-0.22.3-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:81e69b0a0e2537f26d73b4e43ad7bc8c8efb39621639b4434b76a3de50c6966e", size = 446695 }, { url = "https://files.pythonhosted.org/packages/4d/cf/96f1fd75512a017f8e07408b6d5dbeb492d9ed46bfe0555544294f3681b3/rpds_py-0.22.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bc27863442d388870c1809a87507727b799c8460573cfbb6dc0eeaef5a11b5ec", size = 381959 }, { url = "https://files.pythonhosted.org/packages/ab/f0/d1c5b501c8aea85aeb938b555bfdf7612110a2f8cdc21ae0482c93dd0c24/rpds_py-0.22.3-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:e79dd39f1e8c3504be0607e5fc6e86bb60fe3584bec8b782578c3b0fde8d932c", size = 410420 }, { url = "https://files.pythonhosted.org/packages/33/3b/45b6c58fb6aad5a569ae40fb890fc494c6b02203505a5008ee6dc68e65f7/rpds_py-0.22.3-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:e0fa2d4ec53dc51cf7d3bb22e0aa0143966119f42a0c3e4998293a3dd2856b09", size = 557620 }, { url = "https://files.pythonhosted.org/packages/83/62/3fdd2d3d47bf0bb9b931c4c73036b4ab3ec77b25e016ae26fab0f02be2af/rpds_py-0.22.3-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:fda7cb070f442bf80b642cd56483b5548e43d366fe3f39b98e67cce780cded00", size = 584202 }, { url = "https://files.pythonhosted.org/packages/04/f2/5dced98b64874b84ca824292f9cee2e3f30f3bcf231d15a903126684f74d/rpds_py-0.22.3-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:cff63a0272fcd259dcc3be1657b07c929c466b067ceb1c20060e8d10af56f5bf", size = 552787 }, { url = "https://files.pythonhosted.org/packages/67/13/2273dea1204eda0aea0ef55145da96a9aa28b3f88bb5c70e994f69eda7c3/rpds_py-0.22.3-cp310-cp310-win32.whl", hash = "sha256:9bd7228827ec7bb817089e2eb301d907c0d9827a9e558f22f762bb690b131652", size = 220088 }, { url = "https://files.pythonhosted.org/packages/4e/80/8c8176b67ad7f4a894967a7a4014ba039626d96f1d4874d53e409b58d69f/rpds_py-0.22.3-cp310-cp310-win_amd64.whl", hash = "sha256:9beeb01d8c190d7581a4d59522cd3d4b6887040dcfc744af99aa59fef3e041a8", size = 231737 }, { url = "https://files.pythonhosted.org/packages/15/ad/8d1ddf78f2805a71253fcd388017e7b4a0615c22c762b6d35301fef20106/rpds_py-0.22.3-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:d20cfb4e099748ea39e6f7b16c91ab057989712d31761d3300d43134e26e165f", size = 359773 }, { url = "https://files.pythonhosted.org/packages/c8/75/68c15732293a8485d79fe4ebe9045525502a067865fa4278f178851b2d87/rpds_py-0.22.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:68049202f67380ff9aa52f12e92b1c30115f32e6895cd7198fa2a7961621fc5a", size = 349214 }, { url = "https://files.pythonhosted.org/packages/3c/4c/7ce50f3070083c2e1b2bbd0fb7046f3da55f510d19e283222f8f33d7d5f4/rpds_py-0.22.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fb4f868f712b2dd4bcc538b0a0c1f63a2b1d584c925e69a224d759e7070a12d5", size = 380477 }, { url = "https://files.pythonhosted.org/packages/9a/e9/835196a69cb229d5c31c13b8ae603bd2da9a6695f35fe4270d398e1db44c/rpds_py-0.22.3-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:bc51abd01f08117283c5ebf64844a35144a0843ff7b2983e0648e4d3d9f10dbb", size = 386171 }, { url = "https://files.pythonhosted.org/packages/f9/8e/33fc4eba6683db71e91e6d594a2cf3a8fbceb5316629f0477f7ece5e3f75/rpds_py-0.22.3-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:0f3cec041684de9a4684b1572fe28c7267410e02450f4561700ca5a3bc6695a2", size = 422676 }, { url = "https://files.pythonhosted.org/packages/37/47/2e82d58f8046a98bb9497a8319604c92b827b94d558df30877c4b3c6ccb3/rpds_py-0.22.3-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7ef9d9da710be50ff6809fed8f1963fecdfecc8b86656cadfca3bc24289414b0", size = 446152 }, { url = "https://files.pythonhosted.org/packages/e1/78/79c128c3e71abbc8e9739ac27af11dc0f91840a86fce67ff83c65d1ba195/rpds_py-0.22.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:59f4a79c19232a5774aee369a0c296712ad0e77f24e62cad53160312b1c1eaa1", size = 381300 }, { url = "https://files.pythonhosted.org/packages/c9/5b/2e193be0e8b228c1207f31fa3ea79de64dadb4f6a4833111af8145a6bc33/rpds_py-0.22.3-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:1a60bce91f81ddaac922a40bbb571a12c1070cb20ebd6d49c48e0b101d87300d", size = 409636 }, { url = "https://files.pythonhosted.org/packages/c2/3f/687c7100b762d62186a1c1100ffdf99825f6fa5ea94556844bbbd2d0f3a9/rpds_py-0.22.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:e89391e6d60251560f0a8f4bd32137b077a80d9b7dbe6d5cab1cd80d2746f648", size = 556708 }, { url = "https://files.pythonhosted.org/packages/8c/a2/c00cbc4b857e8b3d5e7f7fc4c81e23afd8c138b930f4f3ccf9a41a23e9e4/rpds_py-0.22.3-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:e3fb866d9932a3d7d0c82da76d816996d1667c44891bd861a0f97ba27e84fc74", size = 583554 }, { url = "https://files.pythonhosted.org/packages/d0/08/696c9872cf56effdad9ed617ac072f6774a898d46b8b8964eab39ec562d2/rpds_py-0.22.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:1352ae4f7c717ae8cba93421a63373e582d19d55d2ee2cbb184344c82d2ae55a", size = 552105 }, { url = "https://files.pythonhosted.org/packages/18/1f/4df560be1e994f5adf56cabd6c117e02de7c88ee238bb4ce03ed50da9d56/rpds_py-0.22.3-cp311-cp311-win32.whl", hash = "sha256:b0b4136a252cadfa1adb705bb81524eee47d9f6aab4f2ee4fa1e9d3cd4581f64", size = 220199 }, { url = "https://files.pythonhosted.org/packages/b8/1b/c29b570bc5db8237553002788dc734d6bd71443a2ceac2a58202ec06ef12/rpds_py-0.22.3-cp311-cp311-win_amd64.whl", hash = "sha256:8bd7c8cfc0b8247c8799080fbff54e0b9619e17cdfeb0478ba7295d43f635d7c", size = 231775 }, { url = "https://files.pythonhosted.org/packages/75/47/3383ee3bd787a2a5e65a9b9edc37ccf8505c0a00170e3a5e6ea5fbcd97f7/rpds_py-0.22.3-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:27e98004595899949bd7a7b34e91fa7c44d7a97c40fcaf1d874168bb652ec67e", size = 352334 }, { url = "https://files.pythonhosted.org/packages/40/14/aa6400fa8158b90a5a250a77f2077c0d0cd8a76fce31d9f2b289f04c6dec/rpds_py-0.22.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:1978d0021e943aae58b9b0b196fb4895a25cc53d3956b8e35e0b7682eefb6d56", size = 342111 }, { url = "https://files.pythonhosted.org/packages/7d/06/395a13bfaa8a28b302fb433fb285a67ce0ea2004959a027aea8f9c52bad4/rpds_py-0.22.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:655ca44a831ecb238d124e0402d98f6212ac527a0ba6c55ca26f616604e60a45", size = 384286 }, { url = "https://files.pythonhosted.org/packages/43/52/d8eeaffab047e6b7b7ef7f00d5ead074a07973968ffa2d5820fa131d7852/rpds_py-0.22.3-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:feea821ee2a9273771bae61194004ee2fc33f8ec7db08117ef9147d4bbcbca8e", size = 391739 }, { url = "https://files.pythonhosted.org/packages/83/31/52dc4bde85c60b63719610ed6f6d61877effdb5113a72007679b786377b8/rpds_py-0.22.3-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:22bebe05a9ffc70ebfa127efbc429bc26ec9e9b4ee4d15a740033efda515cf3d", size = 427306 }, { url = "https://files.pythonhosted.org/packages/70/d5/1bab8e389c2261dba1764e9e793ed6830a63f830fdbec581a242c7c46bda/rpds_py-0.22.3-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3af6e48651c4e0d2d166dc1b033b7042ea3f871504b6805ba5f4fe31581d8d38", size = 442717 }, { url = "https://files.pythonhosted.org/packages/82/a1/a45f3e30835b553379b3a56ea6c4eb622cf11e72008229af840e4596a8ea/rpds_py-0.22.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e67ba3c290821343c192f7eae1d8fd5999ca2dc99994114643e2f2d3e6138b15", size = 385721 }, { url = "https://files.pythonhosted.org/packages/a6/27/780c942de3120bdd4d0e69583f9c96e179dfff082f6ecbb46b8d6488841f/rpds_py-0.22.3-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:02fbb9c288ae08bcb34fb41d516d5eeb0455ac35b5512d03181d755d80810059", size = 415824 }, { url = "https://files.pythonhosted.org/packages/94/0b/aa0542ca88ad20ea719b06520f925bae348ea5c1fdf201b7e7202d20871d/rpds_py-0.22.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:f56a6b404f74ab372da986d240e2e002769a7d7102cc73eb238a4f72eec5284e", size = 561227 }, { url = "https://files.pythonhosted.org/packages/0d/92/3ed77d215f82c8f844d7f98929d56cc321bb0bcfaf8f166559b8ec56e5f1/rpds_py-0.22.3-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:0a0461200769ab3b9ab7e513f6013b7a97fdeee41c29b9db343f3c5a8e2b9e61", size = 587424 }, { url = "https://files.pythonhosted.org/packages/09/42/cacaeb047a22cab6241f107644f230e2935d4efecf6488859a7dd82fc47d/rpds_py-0.22.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:8633e471c6207a039eff6aa116e35f69f3156b3989ea3e2d755f7bc41754a4a7", size = 555953 }, { url = "https://files.pythonhosted.org/packages/e6/52/c921dc6d5f5d45b212a456c1f5b17df1a471127e8037eb0972379e39dff4/rpds_py-0.22.3-cp312-cp312-win32.whl", hash = "sha256:593eba61ba0c3baae5bc9be2f5232430453fb4432048de28399ca7376de9c627", size = 221339 }, { url = "https://files.pythonhosted.org/packages/f2/c7/f82b5be1e8456600395366f86104d1bd8d0faed3802ad511ef6d60c30d98/rpds_py-0.22.3-cp312-cp312-win_amd64.whl", hash = "sha256:d115bffdd417c6d806ea9069237a4ae02f513b778e3789a359bc5856e0404cc4", size = 235786 }, { url = "https://files.pythonhosted.org/packages/d0/bf/36d5cc1f2c609ae6e8bf0fc35949355ca9d8790eceb66e6385680c951e60/rpds_py-0.22.3-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:ea7433ce7e4bfc3a85654aeb6747babe3f66eaf9a1d0c1e7a4435bbdf27fea84", size = 351657 }, { url = "https://files.pythonhosted.org/packages/24/2a/f1e0fa124e300c26ea9382e59b2d582cba71cedd340f32d1447f4f29fa4e/rpds_py-0.22.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:6dd9412824c4ce1aca56c47b0991e65bebb7ac3f4edccfd3f156150c96a7bf25", size = 341829 }, { url = "https://files.pythonhosted.org/packages/cf/c2/0da1231dd16953845bed60d1a586fcd6b15ceaeb965f4d35cdc71f70f606/rpds_py-0.22.3-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:20070c65396f7373f5df4005862fa162db5d25d56150bddd0b3e8214e8ef45b4", size = 384220 }, { url = "https://files.pythonhosted.org/packages/c7/73/a4407f4e3a00a9d4b68c532bf2d873d6b562854a8eaff8faa6133b3588ec/rpds_py-0.22.3-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:0b09865a9abc0ddff4e50b5ef65467cd94176bf1e0004184eb915cbc10fc05c5", size = 391009 }, { url = "https://files.pythonhosted.org/packages/a9/c3/04b7353477ab360fe2563f5f0b176d2105982f97cd9ae80a9c5a18f1ae0f/rpds_py-0.22.3-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3453e8d41fe5f17d1f8e9c383a7473cd46a63661628ec58e07777c2fff7196dc", size = 426989 }, { url = "https://files.pythonhosted.org/packages/8d/e6/e4b85b722bcf11398e17d59c0f6049d19cd606d35363221951e6d625fcb0/rpds_py-0.22.3-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f5d36399a1b96e1a5fdc91e0522544580dbebeb1f77f27b2b0ab25559e103b8b", size = 441544 }, { url = "https://files.pythonhosted.org/packages/27/fc/403e65e56f65fff25f2973216974976d3f0a5c3f30e53758589b6dc9b79b/rpds_py-0.22.3-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:009de23c9c9ee54bf11303a966edf4d9087cd43a6003672e6aa7def643d06518", size = 385179 }, { url = "https://files.pythonhosted.org/packages/57/9b/2be9ff9700d664d51fd96b33d6595791c496d2778cb0b2a634f048437a55/rpds_py-0.22.3-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:1aef18820ef3e4587ebe8b3bc9ba6e55892a6d7b93bac6d29d9f631a3b4befbd", size = 415103 }, { url = "https://files.pythonhosted.org/packages/bb/a5/03c2ad8ca10994fcf22dd2150dd1d653bc974fa82d9a590494c84c10c641/rpds_py-0.22.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:f60bd8423be1d9d833f230fdbccf8f57af322d96bcad6599e5a771b151398eb2", size = 560916 }, { url = "https://files.pythonhosted.org/packages/ba/2e/be4fdfc8b5b576e588782b56978c5b702c5a2307024120d8aeec1ab818f0/rpds_py-0.22.3-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:62d9cfcf4948683a18a9aff0ab7e1474d407b7bab2ca03116109f8464698ab16", size = 587062 }, { url = "https://files.pythonhosted.org/packages/67/e0/2034c221937709bf9c542603d25ad43a68b4b0a9a0c0b06a742f2756eb66/rpds_py-0.22.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:9253fc214112405f0afa7db88739294295f0e08466987f1d70e29930262b4c8f", size = 555734 }, { url = "https://files.pythonhosted.org/packages/ea/ce/240bae07b5401a22482b58e18cfbabaa392409b2797da60223cca10d7367/rpds_py-0.22.3-cp313-cp313-win32.whl", hash = "sha256:fb0ba113b4983beac1a2eb16faffd76cb41e176bf58c4afe3e14b9c681f702de", size = 220663 }, { url = "https://files.pythonhosted.org/packages/cb/f0/d330d08f51126330467edae2fa4efa5cec8923c87551a79299380fdea30d/rpds_py-0.22.3-cp313-cp313-win_amd64.whl", hash = "sha256:c58e2339def52ef6b71b8f36d13c3688ea23fa093353f3a4fee2556e62086ec9", size = 235503 }, { url = "https://files.pythonhosted.org/packages/f7/c4/dbe1cc03df013bf2feb5ad00615038050e7859f381e96fb5b7b4572cd814/rpds_py-0.22.3-cp313-cp313t-macosx_10_12_x86_64.whl", hash = "sha256:f82a116a1d03628a8ace4859556fb39fd1424c933341a08ea3ed6de1edb0283b", size = 347698 }, { url = "https://files.pythonhosted.org/packages/a4/3a/684f66dd6b0f37499cad24cd1c0e523541fd768576fa5ce2d0a8799c3cba/rpds_py-0.22.3-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:3dfcbc95bd7992b16f3f7ba05af8a64ca694331bd24f9157b49dadeeb287493b", size = 337330 }, { url = "https://files.pythonhosted.org/packages/82/eb/e022c08c2ce2e8f7683baa313476492c0e2c1ca97227fe8a75d9f0181e95/rpds_py-0.22.3-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:59259dc58e57b10e7e18ce02c311804c10c5a793e6568f8af4dead03264584d1", size = 380022 }, { url = "https://files.pythonhosted.org/packages/e4/21/5a80e653e4c86aeb28eb4fea4add1f72e1787a3299687a9187105c3ee966/rpds_py-0.22.3-cp313-cp313t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:5725dd9cc02068996d4438d397e255dcb1df776b7ceea3b9cb972bdb11260a83", size = 390754 }, { url = "https://files.pythonhosted.org/packages/37/a4/d320a04ae90f72d080b3d74597074e62be0a8ecad7d7321312dfe2dc5a6a/rpds_py-0.22.3-cp313-cp313t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:99b37292234e61325e7a5bb9689e55e48c3f5f603af88b1642666277a81f1fbd", size = 423840 }, { url = "https://files.pythonhosted.org/packages/87/70/674dc47d93db30a6624279284e5631be4c3a12a0340e8e4f349153546728/rpds_py-0.22.3-cp313-cp313t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:27b1d3b3915a99208fee9ab092b8184c420f2905b7d7feb4aeb5e4a9c509b8a1", size = 438970 }, { url = "https://files.pythonhosted.org/packages/3f/64/9500f4d66601d55cadd21e90784cfd5d5f4560e129d72e4339823129171c/rpds_py-0.22.3-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f612463ac081803f243ff13cccc648578e2279295048f2a8d5eb430af2bae6e3", size = 383146 }, { url = "https://files.pythonhosted.org/packages/4d/45/630327addb1d17173adcf4af01336fd0ee030c04798027dfcb50106001e0/rpds_py-0.22.3-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:f73d3fef726b3243a811121de45193c0ca75f6407fe66f3f4e183c983573e130", size = 408294 }, { url = "https://files.pythonhosted.org/packages/5f/ef/8efb3373cee54ea9d9980b772e5690a0c9e9214045a4e7fa35046e399fee/rpds_py-0.22.3-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:3f21f0495edea7fdbaaa87e633a8689cd285f8f4af5c869f27bc8074638ad69c", size = 556345 }, { url = "https://files.pythonhosted.org/packages/54/01/151d3b9ef4925fc8f15bfb131086c12ec3c3d6dd4a4f7589c335bf8e85ba/rpds_py-0.22.3-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:1e9663daaf7a63ceccbbb8e3808fe90415b0757e2abddbfc2e06c857bf8c5e2b", size = 582292 }, { url = "https://files.pythonhosted.org/packages/30/89/35fc7a6cdf3477d441c7aca5e9bbf5a14e0f25152aed7f63f4e0b141045d/rpds_py-0.22.3-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:a76e42402542b1fae59798fab64432b2d015ab9d0c8c47ba7addddbaf7952333", size = 553855 }, { url = "https://files.pythonhosted.org/packages/8f/e0/830c02b2457c4bd20a8c5bb394d31d81f57fbefce2dbdd2e31feff4f7003/rpds_py-0.22.3-cp313-cp313t-win32.whl", hash = "sha256:69803198097467ee7282750acb507fba35ca22cc3b85f16cf45fb01cb9097730", size = 219100 }, { url = "https://files.pythonhosted.org/packages/f8/30/7ac943f69855c2db77407ae363484b915d861702dbba1aa82d68d57f42be/rpds_py-0.22.3-cp313-cp313t-win_amd64.whl", hash = "sha256:f5cf2a0c2bdadf3791b5c205d55a37a54025c6e18a71c71f82bb536cf9a454bf", size = 233794 }, { url = "https://files.pythonhosted.org/packages/db/0f/a8ad17ddac7c880f48d5da50733dd25bfc35ba2be1bec9f23453e8c7a123/rpds_py-0.22.3-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:378753b4a4de2a7b34063d6f95ae81bfa7b15f2c1a04a9518e8644e81807ebea", size = 359735 }, { url = "https://files.pythonhosted.org/packages/0c/41/430903669397ea3ee76865e0b53ea236e8dc0ffbecde47b2c4c783ad6759/rpds_py-0.22.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:3445e07bf2e8ecfeef6ef67ac83de670358abf2996916039b16a218e3d95e97e", size = 348724 }, { url = "https://files.pythonhosted.org/packages/c9/5c/3496f4f0ee818297544f2d5f641c49dde8ae156392e6834b79c0609ba006/rpds_py-0.22.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7b2513ba235829860b13faa931f3b6846548021846ac808455301c23a101689d", size = 381782 }, { url = "https://files.pythonhosted.org/packages/b6/dc/db0523ce0cd16ce579185cc9aa9141992de956d0a9c469ecfd1fb5d54ddc/rpds_py-0.22.3-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:eaf16ae9ae519a0e237a0f528fd9f0197b9bb70f40263ee57ae53c2b8d48aeb3", size = 387036 }, { url = "https://files.pythonhosted.org/packages/85/2a/9525c2427d2c257f877348918136a5d4e1b945c205a256e53bec61e54551/rpds_py-0.22.3-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:583f6a1993ca3369e0f80ba99d796d8e6b1a3a2a442dd4e1a79e652116413091", size = 424566 }, { url = "https://files.pythonhosted.org/packages/b9/1c/f8c012a39794b84069635709f559c0309103d5d74b3f5013916e6ca4f174/rpds_py-0.22.3-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4617e1915a539a0d9a9567795023de41a87106522ff83fbfaf1f6baf8e85437e", size = 447203 }, { url = "https://files.pythonhosted.org/packages/93/f5/c1c772364570d35b98ba64f36ec90c3c6d0b932bc4d8b9b4efef6dc64b07/rpds_py-0.22.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0c150c7a61ed4a4f4955a96626574e9baf1adf772c2fb61ef6a5027e52803543", size = 382283 }, { url = "https://files.pythonhosted.org/packages/10/06/f94f61313f94fc75c3c3aa74563f80bbd990e5b25a7c1a38cee7d5d0309b/rpds_py-0.22.3-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:2fa4331c200c2521512595253f5bb70858b90f750d39b8cbfd67465f8d1b596d", size = 410022 }, { url = "https://files.pythonhosted.org/packages/3f/b0/37ab416a9528419920dfb64886c220f58fcbd66b978e0a91b66e9ee9a993/rpds_py-0.22.3-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:214b7a953d73b5e87f0ebece4a32a5bd83c60a3ecc9d4ec8f1dca968a2d91e99", size = 557817 }, { url = "https://files.pythonhosted.org/packages/2c/5d/9daa18adcd676dd3b2817c8a7cec3f3ebeeb0ce0d05a1b63bf994fc5114f/rpds_py-0.22.3-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:f47ad3d5f3258bd7058d2d506852217865afefe6153a36eb4b6928758041d831", size = 585099 }, { url = "https://files.pythonhosted.org/packages/41/3f/ad4e58035d3f848410aa3d59857b5f238bafab81c8b4a844281f80445d62/rpds_py-0.22.3-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:f276b245347e6e36526cbd4a266a417796fc531ddf391e43574cf6466c492520", size = 552818 }, { url = "https://files.pythonhosted.org/packages/b8/19/123acae8f4cab3c9463097c3ced3cc87c46f405056e249c874940e045309/rpds_py-0.22.3-cp39-cp39-win32.whl", hash = "sha256:bbb232860e3d03d544bc03ac57855cd82ddf19c7a07651a7c0fdb95e9efea8b9", size = 220246 }, { url = "https://files.pythonhosted.org/packages/8b/8d/9db93e48d96ace1f6713c71ce72e2d94b71d82156c37b6a54e0930486f00/rpds_py-0.22.3-cp39-cp39-win_amd64.whl", hash = "sha256:cfbc454a2880389dbb9b5b398e50d439e2e58669160f27b60e5eca11f68ae17c", size = 231932 }, { url = "https://files.pythonhosted.org/packages/8b/63/e29f8ee14fcf383574f73b6bbdcbec0fbc2e5fc36b4de44d1ac389b1de62/rpds_py-0.22.3-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:d48424e39c2611ee1b84ad0f44fb3b2b53d473e65de061e3f460fc0be5f1939d", size = 360786 }, { url = "https://files.pythonhosted.org/packages/d3/e0/771ee28b02a24e81c8c0e645796a371350a2bb6672753144f36ae2d2afc9/rpds_py-0.22.3-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:24e8abb5878e250f2eb0d7859a8e561846f98910326d06c0d51381fed59357bd", size = 350589 }, { url = "https://files.pythonhosted.org/packages/cf/49/abad4c4a1e6f3adf04785a99c247bfabe55ed868133e2d1881200aa5d381/rpds_py-0.22.3-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4b232061ca880db21fa14defe219840ad9b74b6158adb52ddf0e87bead9e8493", size = 381848 }, { url = "https://files.pythonhosted.org/packages/3a/7d/f4bc6d6fbe6af7a0d2b5f2ee77079efef7c8528712745659ec0026888998/rpds_py-0.22.3-pp310-pypy310_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ac0a03221cdb5058ce0167ecc92a8c89e8d0decdc9e99a2ec23380793c4dcb96", size = 387879 }, { url = "https://files.pythonhosted.org/packages/13/b0/575c797377fdcd26cedbb00a3324232e4cb2c5d121f6e4b0dbf8468b12ef/rpds_py-0.22.3-pp310-pypy310_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:eb0c341fa71df5a4595f9501df4ac5abfb5a09580081dffbd1ddd4654e6e9123", size = 423916 }, { url = "https://files.pythonhosted.org/packages/54/78/87157fa39d58f32a68d3326f8a81ad8fb99f49fe2aa7ad9a1b7d544f9478/rpds_py-0.22.3-pp310-pypy310_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:bf9db5488121b596dbfc6718c76092fda77b703c1f7533a226a5a9f65248f8ad", size = 448410 }, { url = "https://files.pythonhosted.org/packages/59/69/860f89996065a88be1b6ff2d60e96a02b920a262d8aadab99e7903986597/rpds_py-0.22.3-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0b8db6b5b2d4491ad5b6bdc2bc7c017eec108acbf4e6785f42a9eb0ba234f4c9", size = 382841 }, { url = "https://files.pythonhosted.org/packages/bd/d7/bc144e10d27e3cb350f98df2492a319edd3caaf52ddfe1293f37a9afbfd7/rpds_py-0.22.3-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:b3d504047aba448d70cf6fa22e06cb09f7cbd761939fdd47604f5e007675c24e", size = 409662 }, { url = "https://files.pythonhosted.org/packages/14/2a/6bed0b05233c291a94c7e89bc76ffa1c619d4e1979fbfe5d96024020c1fb/rpds_py-0.22.3-pp310-pypy310_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:e61b02c3f7a1e0b75e20c3978f7135fd13cb6cf551bf4a6d29b999a88830a338", size = 558221 }, { url = "https://files.pythonhosted.org/packages/11/23/cd8f566de444a137bc1ee5795e47069a947e60810ba4152886fe5308e1b7/rpds_py-0.22.3-pp310-pypy310_pp73-musllinux_1_2_i686.whl", hash = "sha256:e35ba67d65d49080e8e5a1dd40101fccdd9798adb9b050ff670b7d74fa41c566", size = 583780 }, { url = "https://files.pythonhosted.org/packages/8d/63/79c3602afd14d501f751e615a74a59040328da5ef29ed5754ae80d236b84/rpds_py-0.22.3-pp310-pypy310_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:26fd7cac7dd51011a245f29a2cc6489c4608b5a8ce8d75661bb4a1066c52dfbe", size = 553619 }, { url = "https://files.pythonhosted.org/packages/9f/2e/c5c1689e80298d4e94c75b70faada4c25445739d91b94c211244a3ed7ed1/rpds_py-0.22.3-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:177c7c0fce2855833819c98e43c262007f42ce86651ffbb84f37883308cb0e7d", size = 233338 }, { url = "https://files.pythonhosted.org/packages/bc/b7/d2c205723e3b4d75b03215694f0297a1b4b395bf834cb5896ad9bbb90f90/rpds_py-0.22.3-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:bb47271f60660803ad11f4c61b42242b8c1312a31c98c578f79ef9387bbde21c", size = 360594 }, { url = "https://files.pythonhosted.org/packages/d8/8f/c3515f5234cf6055046d4cfe9c80a3742a20acfa7d0b1b290f0d7f56a8db/rpds_py-0.22.3-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:70fb28128acbfd264eda9bf47015537ba3fe86e40d046eb2963d75024be4d055", size = 349594 }, { url = "https://files.pythonhosted.org/packages/6b/98/5b487cb06afc484befe350c87fda37f4ce11333f04f3380aba43dcf5bce2/rpds_py-0.22.3-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:44d61b4b7d0c2c9ac019c314e52d7cbda0ae31078aabd0f22e583af3e0d79723", size = 381138 }, { url = "https://files.pythonhosted.org/packages/5e/3a/12308d2c51b3fdfc173619943b7dc5ba41b4850c47112eeda38d9c54ed12/rpds_py-0.22.3-pp39-pypy39_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:5f0e260eaf54380380ac3808aa4ebe2d8ca28b9087cf411649f96bad6900c728", size = 387828 }, { url = "https://files.pythonhosted.org/packages/17/b2/c242241ab5a2a206e093f24ccbfa519c4bbf10a762ac90bffe1766c225e0/rpds_py-0.22.3-pp39-pypy39_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b25bc607423935079e05619d7de556c91fb6adeae9d5f80868dde3468657994b", size = 424634 }, { url = "https://files.pythonhosted.org/packages/d5/c7/52a1b15012139f3ba740f291f1d03c6b632938ba61bc605f24c101952493/rpds_py-0.22.3-pp39-pypy39_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:fb6116dfb8d1925cbdb52595560584db42a7f664617a1f7d7f6e32f138cdf37d", size = 447862 }, { url = "https://files.pythonhosted.org/packages/55/3e/4d3ed8fd01bad77e8ed101116fe63b03f1011940d9596a8f4d82ac80cacd/rpds_py-0.22.3-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a63cbdd98acef6570c62b92a1e43266f9e8b21e699c363c0fef13bd530799c11", size = 382506 }, { url = "https://files.pythonhosted.org/packages/30/78/df59d6f92470a84369a3757abeae1cfd7f7239c8beb6d948949bf78317d2/rpds_py-0.22.3-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:2b8f60e1b739a74bab7e01fcbe3dddd4657ec685caa04681df9d562ef15b625f", size = 410534 }, { url = "https://files.pythonhosted.org/packages/38/97/ea45d1edd9b753b20084b52dd5db6ee5e1ac3e036a27149972398a413858/rpds_py-0.22.3-pp39-pypy39_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:2e8b55d8517a2fda8d95cb45d62a5a8bbf9dd0ad39c5b25c8833efea07b880ca", size = 557453 }, { url = "https://files.pythonhosted.org/packages/08/cd/3a1b35eb9da27ffbb981cfffd32a01c7655c4431ccb278cb3064f8887462/rpds_py-0.22.3-pp39-pypy39_pp73-musllinux_1_2_i686.whl", hash = "sha256:2de29005e11637e7a2361fa151f780ff8eb2543a0da1413bb951e9f14b699ef3", size = 584412 }, { url = "https://files.pythonhosted.org/packages/87/91/31d1c5aeb1606f71188259e0ba6ed6f5c21a3c72f58b51db6a8bd0aa2b5d/rpds_py-0.22.3-pp39-pypy39_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:666ecce376999bf619756a24ce15bb14c5bfaf04bf00abc7e663ce17c3f34fe7", size = 553446 }, { url = "https://files.pythonhosted.org/packages/e7/ad/03b5ccd1ab492c9dece85b3bf1c96453ab8c47983936fae6880f688f60b3/rpds_py-0.22.3-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:5246b14ca64a8675e0a7161f7af68fe3e910e6b90542b4bfb5439ba752191df6", size = 233013 }, ] [[package]] name = "ruff" version = "0.9.6" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/2a/e1/e265aba384343dd8ddd3083f5e33536cd17e1566c41453a5517b5dd443be/ruff-0.9.6.tar.gz", hash = "sha256:81761592f72b620ec8fa1068a6fd00e98a5ebee342a3642efd84454f3031dca9", size = 3639454 } wheels = [ { url = "https://files.pythonhosted.org/packages/76/e3/3d2c022e687e18cf5d93d6bfa2722d46afc64eaa438c7fbbdd603b3597be/ruff-0.9.6-py3-none-linux_armv6l.whl", hash = "sha256:2f218f356dd2d995839f1941322ff021c72a492c470f0b26a34f844c29cdf5ba", size = 11714128 }, { url = "https://files.pythonhosted.org/packages/e1/22/aff073b70f95c052e5c58153cba735748c9e70107a77d03420d7850710a0/ruff-0.9.6-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:b908ff4df65dad7b251c9968a2e4560836d8f5487c2f0cc238321ed951ea0504", size = 11682539 }, { url = "https://files.pythonhosted.org/packages/75/a7/f5b7390afd98a7918582a3d256cd3e78ba0a26165a467c1820084587cbf9/ruff-0.9.6-py3-none-macosx_11_0_arm64.whl", hash = "sha256:b109c0ad2ececf42e75fa99dc4043ff72a357436bb171900714a9ea581ddef83", size = 11132512 }, { url = "https://files.pythonhosted.org/packages/a6/e3/45de13ef65047fea2e33f7e573d848206e15c715e5cd56095589a7733d04/ruff-0.9.6-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1de4367cca3dac99bcbd15c161404e849bb0bfd543664db39232648dc00112dc", size = 11929275 }, { url = "https://files.pythonhosted.org/packages/7d/f2/23d04cd6c43b2e641ab961ade8d0b5edb212ecebd112506188c91f2a6e6c/ruff-0.9.6-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ac3ee4d7c2c92ddfdaedf0bf31b2b176fa7aa8950efc454628d477394d35638b", size = 11466502 }, { url = "https://files.pythonhosted.org/packages/b5/6f/3a8cf166f2d7f1627dd2201e6cbc4cb81f8b7d58099348f0c1ff7b733792/ruff-0.9.6-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5dc1edd1775270e6aa2386119aea692039781429f0be1e0949ea5884e011aa8e", size = 12676364 }, { url = "https://files.pythonhosted.org/packages/f5/c4/db52e2189983c70114ff2b7e3997e48c8318af44fe83e1ce9517570a50c6/ruff-0.9.6-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:4a091729086dffa4bd070aa5dab7e39cc6b9d62eb2bef8f3d91172d30d599666", size = 13335518 }, { url = "https://files.pythonhosted.org/packages/66/44/545f8a4d136830f08f4d24324e7db957c5374bf3a3f7a6c0bc7be4623a37/ruff-0.9.6-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d1bbc6808bf7b15796cef0815e1dfb796fbd383e7dbd4334709642649625e7c5", size = 12823287 }, { url = "https://files.pythonhosted.org/packages/c5/26/8208ef9ee7431032c143649a9967c3ae1aae4257d95e6f8519f07309aa66/ruff-0.9.6-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:589d1d9f25b5754ff230dce914a174a7c951a85a4e9270613a2b74231fdac2f5", size = 14592374 }, { url = "https://files.pythonhosted.org/packages/31/70/e917781e55ff39c5b5208bda384fd397ffd76605e68544d71a7e40944945/ruff-0.9.6-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dc61dd5131742e21103fbbdcad683a8813be0e3c204472d520d9a5021ca8b217", size = 12500173 }, { url = "https://files.pythonhosted.org/packages/84/f5/e4ddee07660f5a9622a9c2b639afd8f3104988dc4f6ba0b73ffacffa9a8c/ruff-0.9.6-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:5e2d9126161d0357e5c8f30b0bd6168d2c3872372f14481136d13de9937f79b6", size = 11906555 }, { url = "https://files.pythonhosted.org/packages/f1/2b/6ff2fe383667075eef8656b9892e73dd9b119b5e3add51298628b87f6429/ruff-0.9.6-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:68660eab1a8e65babb5229a1f97b46e3120923757a68b5413d8561f8a85d4897", size = 11538958 }, { url = "https://files.pythonhosted.org/packages/3c/db/98e59e90de45d1eb46649151c10a062d5707b5b7f76f64eb1e29edf6ebb1/ruff-0.9.6-py3-none-musllinux_1_2_i686.whl", hash = "sha256:c4cae6c4cc7b9b4017c71114115db0445b00a16de3bcde0946273e8392856f08", size = 12117247 }, { url = "https://files.pythonhosted.org/packages/ec/bc/54e38f6d219013a9204a5a2015c09e7a8c36cedcd50a4b01ac69a550b9d9/ruff-0.9.6-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:19f505b643228b417c1111a2a536424ddde0db4ef9023b9e04a46ed8a1cb4656", size = 12554647 }, { url = "https://files.pythonhosted.org/packages/a5/7d/7b461ab0e2404293c0627125bb70ac642c2e8d55bf590f6fce85f508f1b2/ruff-0.9.6-py3-none-win32.whl", hash = "sha256:194d8402bceef1b31164909540a597e0d913c0e4952015a5b40e28c146121b5d", size = 9949214 }, { url = "https://files.pythonhosted.org/packages/ee/30/c3cee10f915ed75a5c29c1e57311282d1a15855551a64795c1b2bbe5cf37/ruff-0.9.6-py3-none-win_amd64.whl", hash = "sha256:03482d5c09d90d4ee3f40d97578423698ad895c87314c4de39ed2af945633caa", size = 10999914 }, { url = "https://files.pythonhosted.org/packages/e8/a8/d71f44b93e3aa86ae232af1f2126ca7b95c0f515ec135462b3e1f351441c/ruff-0.9.6-py3-none-win_arm64.whl", hash = "sha256:0e2bb706a2be7ddfea4a4af918562fdc1bcb16df255e5fa595bbd800ce322a5a", size = 10177499 }, ] [[package]] name = "secretstorage" version = "3.3.3" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "cryptography" }, { name = "jeepney" }, ] sdist = { url = "https://files.pythonhosted.org/packages/53/a4/f48c9d79cb507ed1373477dbceaba7401fd8a23af63b837fa61f1dcd3691/SecretStorage-3.3.3.tar.gz", hash = "sha256:2403533ef369eca6d2ba81718576c5e0f564d5cca1b58f73a8b23e7d4eeebd77", size = 19739 } wheels = [ { url = "https://files.pythonhosted.org/packages/54/24/b4293291fa1dd830f353d2cb163295742fa87f179fcc8a20a306a81978b7/SecretStorage-3.3.3-py3-none-any.whl", hash = "sha256:f356e6628222568e3af06f2eba8df495efa13b3b63081dafd4f7d9a7b7bc9f99", size = 15221 }, ] [[package]] name = "setuptools" version = "75.8.0" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/92/ec/089608b791d210aec4e7f97488e67ab0d33add3efccb83a056cbafe3a2a6/setuptools-75.8.0.tar.gz", hash = "sha256:c5afc8f407c626b8313a86e10311dd3f661c6cd9c09d4bf8c15c0e11f9f2b0e6", size = 1343222 } wheels = [ { url = "https://files.pythonhosted.org/packages/69/8a/b9dc7678803429e4a3bc9ba462fa3dd9066824d3c607490235c6a796be5a/setuptools-75.8.0-py3-none-any.whl", hash = "sha256:e3982f444617239225d675215d51f6ba05f845d4eec313da4418fdbb56fb27e3", size = 1228782 }, ] [[package]] name = "shellingham" version = "1.5.4" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/58/15/8b3609fd3830ef7b27b655beb4b4e9c62313a4e8da8c676e142cc210d58e/shellingham-1.5.4.tar.gz", hash = "sha256:8dbca0739d487e5bd35ab3ca4b36e11c4078f3a234bfce294b0a0291363404de", size = 10310 } wheels = [ { url = "https://files.pythonhosted.org/packages/e0/f9/0595336914c5619e5f28a1fb793285925a8cd4b432c9da0a987836c7f822/shellingham-1.5.4-py2.py3-none-any.whl", hash = "sha256:7ecfff8f2fd72616f7481040475a65b2bf8af90a56c89140852d1120324e8686", size = 9755 }, ] [[package]] name = "six" version = "1.17.0" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/94/e7/b2c673351809dca68a0e064b6af791aa332cf192da575fd474ed7d6f16a2/six-1.17.0.tar.gz", hash = "sha256:ff70335d468e7eb6ec65b95b99d3a2836546063f63acc5171de367e834932a81", size = 34031 } wheels = [ { url = "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl", hash = "sha256:4721f391ed90541fddacab5acf947aa0d3dc7d27b2e1e8eda2be8970586c3274", size = 11050 }, ] [[package]] name = "smmap" version = "5.0.2" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/44/cd/a040c4b3119bbe532e5b0732286f805445375489fceaec1f48306068ee3b/smmap-5.0.2.tar.gz", hash = "sha256:26ea65a03958fa0c8a1c7e8c7a58fdc77221b8910f6be2131affade476898ad5", size = 22329 } wheels = [ { url = "https://files.pythonhosted.org/packages/04/be/d09147ad1ec7934636ad912901c5fd7667e1c858e19d355237db0d0cd5e4/smmap-5.0.2-py3-none-any.whl", hash = "sha256:b30115f0def7d7531d22a0fb6502488d879e75b260a9db4d0819cfb25403af5e", size = 24303 }, ] [[package]] name = "sniffio" version = "1.3.1" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/a2/87/a6771e1546d97e7e041b6ae58d80074f81b7d5121207425c964ddf5cfdbd/sniffio-1.3.1.tar.gz", hash = "sha256:f4324edc670a0f49750a81b895f35c3adb843cca46f0530f79fc1babb23789dc", size = 20372 } wheels = [ { url = "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl", hash = "sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2", size = 10235 }, ] [[package]] name = "snowballstemmer" version = "2.2.0" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/44/7b/af302bebf22c749c56c9c3e8ae13190b5b5db37a33d9068652e8f73b7089/snowballstemmer-2.2.0.tar.gz", hash = "sha256:09b16deb8547d3412ad7b590689584cd0fe25ec8db3be37788be3810cbf19cb1", size = 86699 } wheels = [ { url = "https://files.pythonhosted.org/packages/ed/dc/c02e01294f7265e63a7315fe086dd1df7dacb9f840a804da846b96d01b96/snowballstemmer-2.2.0-py2.py3-none-any.whl", hash = "sha256:c8e1716e83cc398ae16824e5572ae04e0d9fc2c6b985fb0f900f5f0c96ecba1a", size = 93002 }, ] [[package]] name = "sortedcontainers" version = "2.4.0" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/e8/c4/ba2f8066cceb6f23394729afe52f3bf7adec04bf9ed2c820b39e19299111/sortedcontainers-2.4.0.tar.gz", hash = "sha256:25caa5a06cc30b6b83d11423433f65d1f9d76c4c6a0c90e3379eaa43b9bfdb88", size = 30594 } wheels = [ { url = "https://files.pythonhosted.org/packages/32/46/9cb0e58b2deb7f82b84065f37f3bffeb12413f947f9388e4cac22c4621ce/sortedcontainers-2.4.0-py2.py3-none-any.whl", hash = "sha256:a163dcaede0f1c021485e957a39245190e74249897e2ae4b2aa38595db237ee0", size = 29575 }, ] [[package]] name = "soupsieve" version = "2.6" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/d7/ce/fbaeed4f9fb8b2daa961f90591662df6a86c1abf25c548329a86920aedfb/soupsieve-2.6.tar.gz", hash = "sha256:e2e68417777af359ec65daac1057404a3c8a5455bb8abc36f1a9866ab1a51abb", size = 101569 } wheels = [ { url = "https://files.pythonhosted.org/packages/d1/c2/fe97d779f3ef3b15f05c94a2f1e3d21732574ed441687474db9d342a7315/soupsieve-2.6-py3-none-any.whl", hash = "sha256:e72c4ff06e4fb6e4b5a9f0f55fe6e81514581fca1515028625d0f299c602ccc9", size = 36186 }, ] [[package]] name = "stack-data" version = "0.6.3" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "asttokens" }, { name = "executing" }, { name = "pure-eval" }, ] sdist = { url = "https://files.pythonhosted.org/packages/28/e3/55dcc2cfbc3ca9c29519eb6884dd1415ecb53b0e934862d3559ddcb7e20b/stack_data-0.6.3.tar.gz", hash = "sha256:836a778de4fec4dcd1dcd89ed8abff8a221f58308462e1c4aa2a3cf30148f0b9", size = 44707 } wheels = [ { url = "https://files.pythonhosted.org/packages/f1/7b/ce1eafaf1a76852e2ec9b22edecf1daa58175c090266e9f6c64afcd81d91/stack_data-0.6.3-py3-none-any.whl", hash = "sha256:d5558e0c25a4cb0853cddad3d77da9891a08cb85dd9f9f91b9f8cd66e511e695", size = 24521 }, ] [[package]] name = "stdlibs" version = "2024.12.3" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/c4/19/1bafdce539149fbcae1d173164c297b7b7c9e59a43221555a0d359c132cc/stdlibs-2024.12.3.tar.gz", hash = "sha256:b88cf600ac0b80e3d0de0ad6f2be786786db063bccd14b897547fcd9bd7169be", size = 19440 } wheels = [ { url = "https://files.pythonhosted.org/packages/7c/c9/fd5ba168c09b021b71590045c5a4d9fa6923a8e88d0f52721fdbd011ca2e/stdlibs-2024.12.3-py3-none-any.whl", hash = "sha256:51be16dce7cac80c836eb0413b9397093e68857fa13eb53893b0d8c042565f93", size = 57125 }, ] [[package]] name = "stevedore" version = "5.4.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "pbr" }, ] sdist = { url = "https://files.pythonhosted.org/packages/4a/e9/4eedccff8332cc40cc60ddd3b28d4c3e255ee7e9c65679fa4533ab98f598/stevedore-5.4.0.tar.gz", hash = "sha256:79e92235ecb828fe952b6b8b0c6c87863248631922c8e8e0fa5b17b232c4514d", size = 513899 } wheels = [ { url = "https://files.pythonhosted.org/packages/8f/73/d0091d22a65b55e8fb6aca7b3b6713b5a261dd01cec4cfd28ed127ac0cfc/stevedore-5.4.0-py3-none-any.whl", hash = "sha256:b0be3c4748b3ea7b854b265dcb4caa891015e442416422be16f8b31756107857", size = 49534 }, ] [[package]] name = "termcolor" version = "2.5.0" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/37/72/88311445fd44c455c7d553e61f95412cf89054308a1aa2434ab835075fc5/termcolor-2.5.0.tar.gz", hash = "sha256:998d8d27da6d48442e8e1f016119076b690d962507531df4890fcd2db2ef8a6f", size = 13057 } wheels = [ { url = "https://files.pythonhosted.org/packages/7f/be/df630c387a0a054815d60be6a97eb4e8f17385d5d6fe660e1c02750062b4/termcolor-2.5.0-py3-none-any.whl", hash = "sha256:37b17b5fc1e604945c2642c872a3764b5d547a48009871aea3edd3afa180afb8", size = 7755 }, ] [[package]] name = "text-unidecode" version = "1.3" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/ab/e2/e9a00f0ccb71718418230718b3d900e71a5d16e701a3dae079a21e9cd8f8/text-unidecode-1.3.tar.gz", hash = "sha256:bad6603bb14d279193107714b288be206cac565dfa49aa5b105294dd5c4aab93", size = 76885 } wheels = [ { url = "https://files.pythonhosted.org/packages/a6/a5/c0b6468d3824fe3fde30dbb5e1f687b291608f9473681bbf7dabbf5a87d7/text_unidecode-1.3-py2.py3-none-any.whl", hash = "sha256:1311f10e8b895935241623731c2ba64f4c455287888b18189350b67134a822e8", size = 78154 }, ] [[package]] name = "tinycss2" version = "1.4.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "webencodings" }, ] sdist = { url = "https://files.pythonhosted.org/packages/7a/fd/7a5ee21fd08ff70d3d33a5781c255cbe779659bd03278feb98b19ee550f4/tinycss2-1.4.0.tar.gz", hash = "sha256:10c0972f6fc0fbee87c3edb76549357415e94548c1ae10ebccdea16fb404a9b7", size = 87085 } wheels = [ { url = "https://files.pythonhosted.org/packages/e6/34/ebdc18bae6aa14fbee1a08b63c015c72b64868ff7dae68808ab500c492e2/tinycss2-1.4.0-py3-none-any.whl", hash = "sha256:3a49cf47b7675da0b15d0c6e1df8df4ebd96e9394bb905a5775adb0d884c5289", size = 26610 }, ] [[package]] name = "toml" version = "0.10.2" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/be/ba/1f744cdc819428fc6b5084ec34d9b30660f6f9daaf70eead706e3203ec3c/toml-0.10.2.tar.gz", hash = "sha256:b3bda1d108d5dd99f4a20d24d9c348e91c4db7ab1b749200bded2f839ccbe68f", size = 22253 } wheels = [ { url = "https://files.pythonhosted.org/packages/44/6f/7120676b6d73228c96e17f1f794d8ab046fc910d781c8d151120c3f1569e/toml-0.10.2-py2.py3-none-any.whl", hash = "sha256:806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b", size = 16588 }, ] [[package]] name = "tomli" version = "2.2.1" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/18/87/302344fed471e44a87289cf4967697d07e532f2421fdaf868a303cbae4ff/tomli-2.2.1.tar.gz", hash = "sha256:cd45e1dc79c835ce60f7404ec8119f2eb06d38b1deba146f07ced3bbc44505ff", size = 17175 } wheels = [ { url = "https://files.pythonhosted.org/packages/43/ca/75707e6efa2b37c77dadb324ae7d9571cb424e61ea73fad7c56c2d14527f/tomli-2.2.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:678e4fa69e4575eb77d103de3df8a895e1591b48e740211bd1067378c69e8249", size = 131077 }, { url = "https://files.pythonhosted.org/packages/c7/16/51ae563a8615d472fdbffc43a3f3d46588c264ac4f024f63f01283becfbb/tomli-2.2.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:023aa114dd824ade0100497eb2318602af309e5a55595f76b626d6d9f3b7b0a6", size = 123429 }, { url = "https://files.pythonhosted.org/packages/f1/dd/4f6cd1e7b160041db83c694abc78e100473c15d54620083dbd5aae7b990e/tomli-2.2.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ece47d672db52ac607a3d9599a9d48dcb2f2f735c6c2d1f34130085bb12b112a", size = 226067 }, { url = "https://files.pythonhosted.org/packages/a9/6b/c54ede5dc70d648cc6361eaf429304b02f2871a345bbdd51e993d6cdf550/tomli-2.2.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6972ca9c9cc9f0acaa56a8ca1ff51e7af152a9f87fb64623e31d5c83700080ee", size = 236030 }, { url = "https://files.pythonhosted.org/packages/1f/47/999514fa49cfaf7a92c805a86c3c43f4215621855d151b61c602abb38091/tomli-2.2.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c954d2250168d28797dd4e3ac5cf812a406cd5a92674ee4c8f123c889786aa8e", size = 240898 }, { url = "https://files.pythonhosted.org/packages/73/41/0a01279a7ae09ee1573b423318e7934674ce06eb33f50936655071d81a24/tomli-2.2.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:8dd28b3e155b80f4d54beb40a441d366adcfe740969820caf156c019fb5c7ec4", size = 229894 }, { url = "https://files.pythonhosted.org/packages/55/18/5d8bc5b0a0362311ce4d18830a5d28943667599a60d20118074ea1b01bb7/tomli-2.2.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:e59e304978767a54663af13c07b3d1af22ddee3bb2fb0618ca1593e4f593a106", size = 245319 }, { url = "https://files.pythonhosted.org/packages/92/a3/7ade0576d17f3cdf5ff44d61390d4b3febb8a9fc2b480c75c47ea048c646/tomli-2.2.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:33580bccab0338d00994d7f16f4c4ec25b776af3ffaac1ed74e0b3fc95e885a8", size = 238273 }, { url = "https://files.pythonhosted.org/packages/72/6f/fa64ef058ac1446a1e51110c375339b3ec6be245af9d14c87c4a6412dd32/tomli-2.2.1-cp311-cp311-win32.whl", hash = "sha256:465af0e0875402f1d226519c9904f37254b3045fc5084697cefb9bdde1ff99ff", size = 98310 }, { url = "https://files.pythonhosted.org/packages/6a/1c/4a2dcde4a51b81be3530565e92eda625d94dafb46dbeb15069df4caffc34/tomli-2.2.1-cp311-cp311-win_amd64.whl", hash = "sha256:2d0f2fdd22b02c6d81637a3c95f8cd77f995846af7414c5c4b8d0545afa1bc4b", size = 108309 }, { url = "https://files.pythonhosted.org/packages/52/e1/f8af4c2fcde17500422858155aeb0d7e93477a0d59a98e56cbfe75070fd0/tomli-2.2.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:4a8f6e44de52d5e6c657c9fe83b562f5f4256d8ebbfe4ff922c495620a7f6cea", size = 132762 }, { url = "https://files.pythonhosted.org/packages/03/b8/152c68bb84fc00396b83e7bbddd5ec0bd3dd409db4195e2a9b3e398ad2e3/tomli-2.2.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:8d57ca8095a641b8237d5b079147646153d22552f1c637fd3ba7f4b0b29167a8", size = 123453 }, { url = "https://files.pythonhosted.org/packages/c8/d6/fc9267af9166f79ac528ff7e8c55c8181ded34eb4b0e93daa767b8841573/tomli-2.2.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4e340144ad7ae1533cb897d406382b4b6fede8890a03738ff1683af800d54192", size = 233486 }, { url = "https://files.pythonhosted.org/packages/5c/51/51c3f2884d7bab89af25f678447ea7d297b53b5a3b5730a7cb2ef6069f07/tomli-2.2.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:db2b95f9de79181805df90bedc5a5ab4c165e6ec3fe99f970d0e302f384ad222", size = 242349 }, { url = "https://files.pythonhosted.org/packages/ab/df/bfa89627d13a5cc22402e441e8a931ef2108403db390ff3345c05253935e/tomli-2.2.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:40741994320b232529c802f8bc86da4e1aa9f413db394617b9a256ae0f9a7f77", size = 252159 }, { url = "https://files.pythonhosted.org/packages/9e/6e/fa2b916dced65763a5168c6ccb91066f7639bdc88b48adda990db10c8c0b/tomli-2.2.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:400e720fe168c0f8521520190686ef8ef033fb19fc493da09779e592861b78c6", size = 237243 }, { url = "https://files.pythonhosted.org/packages/b4/04/885d3b1f650e1153cbb93a6a9782c58a972b94ea4483ae4ac5cedd5e4a09/tomli-2.2.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:02abe224de6ae62c19f090f68da4e27b10af2b93213d36cf44e6e1c5abd19fdd", size = 259645 }, { url = "https://files.pythonhosted.org/packages/9c/de/6b432d66e986e501586da298e28ebeefd3edc2c780f3ad73d22566034239/tomli-2.2.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:b82ebccc8c8a36f2094e969560a1b836758481f3dc360ce9a3277c65f374285e", size = 244584 }, { url = "https://files.pythonhosted.org/packages/1c/9a/47c0449b98e6e7d1be6cbac02f93dd79003234ddc4aaab6ba07a9a7482e2/tomli-2.2.1-cp312-cp312-win32.whl", hash = "sha256:889f80ef92701b9dbb224e49ec87c645ce5df3fa2cc548664eb8a25e03127a98", size = 98875 }, { url = "https://files.pythonhosted.org/packages/ef/60/9b9638f081c6f1261e2688bd487625cd1e660d0a85bd469e91d8db969734/tomli-2.2.1-cp312-cp312-win_amd64.whl", hash = "sha256:7fc04e92e1d624a4a63c76474610238576942d6b8950a2d7f908a340494e67e4", size = 109418 }, { url = "https://files.pythonhosted.org/packages/04/90/2ee5f2e0362cb8a0b6499dc44f4d7d48f8fff06d28ba46e6f1eaa61a1388/tomli-2.2.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:f4039b9cbc3048b2416cc57ab3bda989a6fcf9b36cf8937f01a6e731b64f80d7", size = 132708 }, { url = "https://files.pythonhosted.org/packages/c0/ec/46b4108816de6b385141f082ba99e315501ccd0a2ea23db4a100dd3990ea/tomli-2.2.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:286f0ca2ffeeb5b9bd4fcc8d6c330534323ec51b2f52da063b11c502da16f30c", size = 123582 }, { url = "https://files.pythonhosted.org/packages/a0/bd/b470466d0137b37b68d24556c38a0cc819e8febe392d5b199dcd7f578365/tomli-2.2.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a92ef1a44547e894e2a17d24e7557a5e85a9e1d0048b0b5e7541f76c5032cb13", size = 232543 }, { url = "https://files.pythonhosted.org/packages/d9/e5/82e80ff3b751373f7cead2815bcbe2d51c895b3c990686741a8e56ec42ab/tomli-2.2.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9316dc65bed1684c9a98ee68759ceaed29d229e985297003e494aa825ebb0281", size = 241691 }, { url = "https://files.pythonhosted.org/packages/05/7e/2a110bc2713557d6a1bfb06af23dd01e7dde52b6ee7dadc589868f9abfac/tomli-2.2.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e85e99945e688e32d5a35c1ff38ed0b3f41f43fad8df0bdf79f72b2ba7bc5272", size = 251170 }, { url = "https://files.pythonhosted.org/packages/64/7b/22d713946efe00e0adbcdfd6d1aa119ae03fd0b60ebed51ebb3fa9f5a2e5/tomli-2.2.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:ac065718db92ca818f8d6141b5f66369833d4a80a9d74435a268c52bdfa73140", size = 236530 }, { url = "https://files.pythonhosted.org/packages/38/31/3a76f67da4b0cf37b742ca76beaf819dca0ebef26d78fc794a576e08accf/tomli-2.2.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:d920f33822747519673ee656a4b6ac33e382eca9d331c87770faa3eef562aeb2", size = 258666 }, { url = "https://files.pythonhosted.org/packages/07/10/5af1293da642aded87e8a988753945d0cf7e00a9452d3911dd3bb354c9e2/tomli-2.2.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:a198f10c4d1b1375d7687bc25294306e551bf1abfa4eace6650070a5c1ae2744", size = 243954 }, { url = "https://files.pythonhosted.org/packages/5b/b9/1ed31d167be802da0fc95020d04cd27b7d7065cc6fbefdd2f9186f60d7bd/tomli-2.2.1-cp313-cp313-win32.whl", hash = "sha256:d3f5614314d758649ab2ab3a62d4f2004c825922f9e370b29416484086b264ec", size = 98724 }, { url = "https://files.pythonhosted.org/packages/c7/32/b0963458706accd9afcfeb867c0f9175a741bf7b19cd424230714d722198/tomli-2.2.1-cp313-cp313-win_amd64.whl", hash = "sha256:a38aa0308e754b0e3c67e344754dff64999ff9b513e691d0e786265c93583c69", size = 109383 }, { url = "https://files.pythonhosted.org/packages/6e/c2/61d3e0f47e2b74ef40a68b9e6ad5984f6241a942f7cd3bbfbdbd03861ea9/tomli-2.2.1-py3-none-any.whl", hash = "sha256:cb55c73c5f4408779d0cf3eef9f762b9c9f147a77de7b258bef0a5628adc85cc", size = 14257 }, ] [[package]] name = "tomli-w" version = "1.2.0" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/19/75/241269d1da26b624c0d5e110e8149093c759b7a286138f4efd61a60e75fe/tomli_w-1.2.0.tar.gz", hash = "sha256:2dd14fac5a47c27be9cd4c976af5a12d87fb1f0b4512f81d69cce3b35ae25021", size = 7184 } wheels = [ { url = "https://files.pythonhosted.org/packages/c7/18/c86eb8e0202e32dd3df50d43d7ff9854f8e0603945ff398974c1d91ac1ef/tomli_w-1.2.0-py3-none-any.whl", hash = "sha256:188306098d013b691fcadc011abd66727d3c414c571bb01b1a174ba8c983cf90", size = 6675 }, ] [[package]] name = "tomlkit" version = "0.13.2" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/b1/09/a439bec5888f00a54b8b9f05fa94d7f901d6735ef4e55dcec9bc37b5d8fa/tomlkit-0.13.2.tar.gz", hash = "sha256:fff5fe59a87295b278abd31bec92c15d9bc4a06885ab12bcea52c71119392e79", size = 192885 } wheels = [ { url = "https://files.pythonhosted.org/packages/f9/b6/a447b5e4ec71e13871be01ba81f5dfc9d0af7e473da256ff46bc0e24026f/tomlkit-0.13.2-py3-none-any.whl", hash = "sha256:7a974427f6e119197f670fbbbeae7bef749a6c14e793db934baefc1b5f03efde", size = 37955 }, ] [[package]] name = "tornado" version = "6.4.2" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/59/45/a0daf161f7d6f36c3ea5fc0c2de619746cc3dd4c76402e9db545bd920f63/tornado-6.4.2.tar.gz", hash = "sha256:92bad5b4746e9879fd7bf1eb21dce4e3fc5128d71601f80005afa39237ad620b", size = 501135 } wheels = [ { url = "https://files.pythonhosted.org/packages/26/7e/71f604d8cea1b58f82ba3590290b66da1e72d840aeb37e0d5f7291bd30db/tornado-6.4.2-cp38-abi3-macosx_10_9_universal2.whl", hash = "sha256:e828cce1123e9e44ae2a50a9de3055497ab1d0aeb440c5ac23064d9e44880da1", size = 436299 }, { url = "https://files.pythonhosted.org/packages/96/44/87543a3b99016d0bf54fdaab30d24bf0af2e848f1d13d34a3a5380aabe16/tornado-6.4.2-cp38-abi3-macosx_10_9_x86_64.whl", hash = "sha256:072ce12ada169c5b00b7d92a99ba089447ccc993ea2143c9ede887e0937aa803", size = 434253 }, { url = "https://files.pythonhosted.org/packages/cb/fb/fdf679b4ce51bcb7210801ef4f11fdac96e9885daa402861751353beea6e/tornado-6.4.2-cp38-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1a017d239bd1bb0919f72af256a970624241f070496635784d9bf0db640d3fec", size = 437602 }, { url = "https://files.pythonhosted.org/packages/4f/3b/e31aeffffc22b475a64dbeb273026a21b5b566f74dee48742817626c47dc/tornado-6.4.2-cp38-abi3-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c36e62ce8f63409301537222faffcef7dfc5284f27eec227389f2ad11b09d946", size = 436972 }, { url = "https://files.pythonhosted.org/packages/22/55/b78a464de78051a30599ceb6983b01d8f732e6f69bf37b4ed07f642ac0fc/tornado-6.4.2-cp38-abi3-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bca9eb02196e789c9cb5c3c7c0f04fb447dc2adffd95265b2c7223a8a615ccbf", size = 437173 }, { url = "https://files.pythonhosted.org/packages/79/5e/be4fb0d1684eb822c9a62fb18a3e44a06188f78aa466b2ad991d2ee31104/tornado-6.4.2-cp38-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:304463bd0772442ff4d0f5149c6f1c2135a1fae045adf070821c6cdc76980634", size = 437892 }, { url = "https://files.pythonhosted.org/packages/f5/33/4f91fdd94ea36e1d796147003b490fe60a0215ac5737b6f9c65e160d4fe0/tornado-6.4.2-cp38-abi3-musllinux_1_2_i686.whl", hash = "sha256:c82c46813ba483a385ab2a99caeaedf92585a1f90defb5693351fa7e4ea0bf73", size = 437334 }, { url = "https://files.pythonhosted.org/packages/2b/ae/c1b22d4524b0e10da2f29a176fb2890386f7bd1f63aacf186444873a88a0/tornado-6.4.2-cp38-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:932d195ca9015956fa502c6b56af9eb06106140d844a335590c1ec7f5277d10c", size = 437261 }, { url = "https://files.pythonhosted.org/packages/b5/25/36dbd49ab6d179bcfc4c6c093a51795a4f3bed380543a8242ac3517a1751/tornado-6.4.2-cp38-abi3-win32.whl", hash = "sha256:2876cef82e6c5978fde1e0d5b1f919d756968d5b4282418f3146b79b58556482", size = 438463 }, { url = "https://files.pythonhosted.org/packages/61/cc/58b1adeb1bb46228442081e746fcdbc4540905c87e8add7c277540934edb/tornado-6.4.2-cp38-abi3-win_amd64.whl", hash = "sha256:908b71bf3ff37d81073356a5fadcc660eb10c1476ee6e2725588626ce7e5ca38", size = 438907 }, ] [[package]] name = "traitlets" version = "5.14.3" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/eb/79/72064e6a701c2183016abbbfedaba506d81e30e232a68c9f0d6f6fcd1574/traitlets-5.14.3.tar.gz", hash = "sha256:9ed0579d3502c94b4b3732ac120375cda96f923114522847de4b3bb98b96b6b7", size = 161621 } wheels = [ { url = "https://files.pythonhosted.org/packages/00/c0/8f5d070730d7836adc9c9b6408dec68c6ced86b304a9b26a14df072a6e8c/traitlets-5.14.3-py3-none-any.whl", hash = "sha256:b74e89e397b1ed28cc831db7aea759ba6640cb3de13090ca145426688ff1ac4f", size = 85359 }, ] [[package]] name = "trove-classifiers" version = "2025.1.15.22" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/f3/cb/8f6a91c74049180e395590901834d68bef5d6a2ce4c9ca9792cfadc1b9b4/trove_classifiers-2025.1.15.22.tar.gz", hash = "sha256:90af74358d3a01b3532bc7b3c88d8c6a094c2fd50a563d13d9576179326d7ed9", size = 16236 } wheels = [ { url = "https://files.pythonhosted.org/packages/2b/c5/6422dbc59954389b20b2aba85b737ab4a552e357e7ea14b52f40312e7c84/trove_classifiers-2025.1.15.22-py3-none-any.whl", hash = "sha256:5f19c789d4f17f501d36c94dbbf969fb3e8c2784d008e6f5164dd2c3d6a2b07c", size = 13610 }, ] [[package]] name = "typer" version = "0.15.1" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "click" }, { name = "rich" }, { name = "shellingham" }, { name = "typing-extensions" }, ] sdist = { url = "https://files.pythonhosted.org/packages/cb/ce/dca7b219718afd37a0068f4f2530a727c2b74a8b6e8e0c0080a4c0de4fcd/typer-0.15.1.tar.gz", hash = "sha256:a0588c0a7fa68a1978a069818657778f86abe6ff5ea6abf472f940a08bfe4f0a", size = 99789 } wheels = [ { url = "https://files.pythonhosted.org/packages/d0/cc/0a838ba5ca64dc832aa43f727bd586309846b0ffb2ce52422543e6075e8a/typer-0.15.1-py3-none-any.whl", hash = "sha256:7994fb7b8155b64d3402518560648446072864beefd44aa2dc36972a5972e847", size = 44908 }, ] [[package]] name = "types-colorama" version = "0.4.15.20240311" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/59/73/0fb0b9fe4964b45b2a06ed41b60c352752626db46aa0fb70a49a9e283a75/types-colorama-0.4.15.20240311.tar.gz", hash = "sha256:a28e7f98d17d2b14fb9565d32388e419f4108f557a7d939a66319969b2b99c7a", size = 5608 } wheels = [ { url = "https://files.pythonhosted.org/packages/b7/83/6944b4fa01efb2e63ac62b791a8ddf0fee358f93be9f64b8f152648ad9d3/types_colorama-0.4.15.20240311-py3-none-any.whl", hash = "sha256:6391de60ddc0db3f147e31ecb230006a6823e81e380862ffca1e4695c13a0b8e", size = 5840 }, ] [[package]] name = "types-python-dateutil" version = "2.9.0.20241206" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/a9/60/47d92293d9bc521cd2301e423a358abfac0ad409b3a1606d8fbae1321961/types_python_dateutil-2.9.0.20241206.tar.gz", hash = "sha256:18f493414c26ffba692a72369fea7a154c502646301ebfe3d56a04b3767284cb", size = 13802 } wheels = [ { url = "https://files.pythonhosted.org/packages/0f/b3/ca41df24db5eb99b00d97f89d7674a90cb6b3134c52fb8121b6d8d30f15c/types_python_dateutil-2.9.0.20241206-py3-none-any.whl", hash = "sha256:e248a4bc70a486d3e3ec84d0dc30eec3a5f979d6e7ee4123ae043eedbb987f53", size = 14384 }, ] [[package]] name = "types-setuptools" version = "75.8.0.20250110" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/f7/42/5713e90d4f9683f2301d900f33e4fc2405ad8ac224dda30f6cb7f4cd215b/types_setuptools-75.8.0.20250110.tar.gz", hash = "sha256:96f7ec8bbd6e0a54ea180d66ad68ad7a1d7954e7281a710ea2de75e355545271", size = 48185 } wheels = [ { url = "https://files.pythonhosted.org/packages/cf/a3/dbfd106751b11c728cec21cc62cbfe7ff7391b935c4b6e8f0bdc2e6fd541/types_setuptools-75.8.0.20250110-py3-none-any.whl", hash = "sha256:a9f12980bbf9bcdc23ecd80755789085bad6bfce4060c2275bc2b4ca9f2bc480", size = 71521 }, ] [[package]] name = "types-toml" version = "0.10.8.20240310" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/86/47/3e4c75042792bff8e90d7991aa5c51812cc668828cc6cce711e97f63a607/types-toml-0.10.8.20240310.tar.gz", hash = "sha256:3d41501302972436a6b8b239c850b26689657e25281b48ff0ec06345b8830331", size = 4392 } wheels = [ { url = "https://files.pythonhosted.org/packages/da/a2/d32ab58c0b216912638b140ab2170ee4b8644067c293b170e19fba340ccc/types_toml-0.10.8.20240310-py3-none-any.whl", hash = "sha256:627b47775d25fa29977d9c70dc0cbab3f314f32c8d8d0c012f2ef5de7aaec05d", size = 4777 }, ] [[package]] name = "typing-extensions" version = "4.12.2" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/df/db/f35a00659bc03fec321ba8bce9420de607a1d37f8342eee1863174c69557/typing_extensions-4.12.2.tar.gz", hash = "sha256:1a7ead55c7e559dd4dee8856e3a88b41225abfe1ce8df57b7c13915fe121ffb8", size = 85321 } wheels = [ { url = "https://files.pythonhosted.org/packages/26/9f/ad63fc0248c5379346306f8668cda6e2e2e9c95e01216d2b8ffd9ff037d0/typing_extensions-4.12.2-py3-none-any.whl", hash = "sha256:04e5ca0351e0f3f85c6853954072df659d0d13fac324d0072316b67d7794700d", size = 37438 }, ] [[package]] name = "urllib3" version = "2.3.0" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/aa/63/e53da845320b757bf29ef6a9062f5c669fe997973f966045cb019c3f4b66/urllib3-2.3.0.tar.gz", hash = "sha256:f8c5449b3cf0861679ce7e0503c7b44b5ec981bec0d1d3795a07f1ba96f0204d", size = 307268 } wheels = [ { url = "https://files.pythonhosted.org/packages/c8/19/4ec628951a74043532ca2cf5d97b7b14863931476d117c471e8e2b1eb39f/urllib3-2.3.0-py3-none-any.whl", hash = "sha256:1cee9ad369867bfdbbb48b7dd50374c0967a0bb7710050facf0dd6911440e3df", size = 128369 }, ] [[package]] name = "userpath" version = "1.9.2" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "click" }, ] sdist = { url = "https://files.pythonhosted.org/packages/d5/b7/30753098208505d7ff9be5b3a32112fb8a4cb3ddfccbbb7ba9973f2e29ff/userpath-1.9.2.tar.gz", hash = "sha256:6c52288dab069257cc831846d15d48133522455d4677ee69a9781f11dbefd815", size = 11140 } wheels = [ { url = "https://files.pythonhosted.org/packages/43/99/3ec6335ded5b88c2f7ed25c56ffd952546f7ed007ffb1e1539dc3b57015a/userpath-1.9.2-py3-none-any.whl", hash = "sha256:2cbf01a23d655a1ff8fc166dfb78da1b641d1ceabf0fe5f970767d380b14e89d", size = 9065 }, ] [[package]] name = "uv" version = "0.5.24" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/2e/f9/248e790785008d0486e87024c9ac712e94d77c66d269d853eed94d74c7a0/uv-0.5.24.tar.gz", hash = "sha256:b7895b66a182bf5e5b88e470ab04beaf76361a64970db6058363293a18c9dd2a", size = 2683917 } wheels = [ { url = "https://files.pythonhosted.org/packages/86/83/3f1dbd0c23bbaaac95f42daa893862f04a6a4b12ee9aa107961230c2d877/uv-0.5.24-py3-none-linux_armv6l.whl", hash = "sha256:13f4f1e36c2b566c19d6fefd09cca5a2a6e8b1cf2ffa16b670351d0eed0c7d4f", size = 15314400 }, { url = "https://files.pythonhosted.org/packages/f8/0a/0c1579c28cd794a8004213300fbd8e0d23accfa61b95cfde26da09fb30d6/uv-0.5.24-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:188bacdbe39c7f76ad1999ce0dee0dfd2b79d248e121498bbaf94ba6089fb7ee", size = 15541096 }, { url = "https://files.pythonhosted.org/packages/83/34/398f9b69ecc6ec5cecd3ea561681cd067162b2d0bc3ec1619948ca564b2b/uv-0.5.24-py3-none-macosx_11_0_arm64.whl", hash = "sha256:f2ccd95cecfcc9e106b9d8d154f6bfc59d8263952f72a720d0158f3b94dc69cb", size = 14426323 }, { url = "https://files.pythonhosted.org/packages/c3/23/4af395cdaa68b02a724e159b42d0e2fb5985b807b36aabea5160ac5d7337/uv-0.5.24-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.musllinux_1_1_aarch64.whl", hash = "sha256:d36da9ab6291eaac151695247cdfb3049e6416d6c210c9890ffcda6d0aa6ad19", size = 14869237 }, { url = "https://files.pythonhosted.org/packages/a1/b0/aa8af618b0d7fbe349a62b4e3641041a894e994b0431289aab5b9c0cca13/uv-0.5.24-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:d7421d59c80bc805103f1030777f909904feab338620db5b5d81f9c10767304d", size = 15110487 }, { url = "https://files.pythonhosted.org/packages/21/e4/f249caa7bfed27f68931ef9ec364cfd536dea2ea06c9279af6a014e2a5e1/uv-0.5.24-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:455d23e0f41577eb9edbdac8e41d37875cb2885758760acee96469084f31571c", size = 15834535 }, { url = "https://files.pythonhosted.org/packages/3d/f2/32f3f4de7cebaefc2259606ad5a3909efdabf1795078a3aaec892f008b34/uv-0.5.24-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:cfcabf26314411dde69c7a62e9757d5688aa475731c7a3b3749f389488121768", size = 16779355 }, { url = "https://files.pythonhosted.org/packages/f5/12/219a90b663706c4a75609edff4bd4b86b9a6c2ff5ec3d156e27ab62f1cf3/uv-0.5.24-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ac8919fc145aeba090adce202e470c21f2df7dfcfa01ca67a9575d41adbf3de5", size = 16502313 }, { url = "https://files.pythonhosted.org/packages/51/8c/72a2b033bbd35fed1aee42a771bbc9aa09570bde7c55605056d558a423ba/uv-0.5.24-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:57b473602e7f3f356ba4d2cb5e2c6c7c691f21dbbffd7202c12fc9db29b7ad7a", size = 20823843 }, { url = "https://files.pythonhosted.org/packages/c7/04/9050b089ffa18ce665f3f0cd82c8f333789fea1e775a172ec389560fc99b/uv-0.5.24-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a47acfda27654c212af6aeec0b8d12fc0150295b7e6afabbdc741a7eb39d898f", size = 16164564 }, { url = "https://files.pythonhosted.org/packages/2c/1b/d38166a3a254061c862a4a99b49ec9e3b98be254f33e24caeeb5c1184252/uv-0.5.24-py3-none-manylinux_2_28_aarch64.whl", hash = "sha256:1e933341300f107d228608af9cc23e08c3a386c0077181db23b4cd26535c64d7", size = 15151622 }, { url = "https://files.pythonhosted.org/packages/6f/5f/365450f8cb40fcc070f3b288b07edf40c07529c423e51e6b807821dd0d3d/uv-0.5.24-py3-none-musllinux_1_1_armv7l.whl", hash = "sha256:421304f2b31799f9f926faa75add2b7bbf653e850b9f97c08cb74e5fb5e7f661", size = 15054207 }, { url = "https://files.pythonhosted.org/packages/6e/08/91eefd0a2428151e8b8b1b7b55bfd4f055c91320ed0284713952a980e24d/uv-0.5.24-py3-none-musllinux_1_1_i686.whl", hash = "sha256:d3a9e63b098055830b58b47552ea4fc38c94a95b5f2de44a8d288ef5decce265", size = 15492772 }, { url = "https://files.pythonhosted.org/packages/bd/9f/8260e02540d8982e5ecc5e6174f030e8e25ea845e43d25dbe566ceee6af3/uv-0.5.24-py3-none-musllinux_1_1_x86_64.whl", hash = "sha256:6640a2cb919cc04c0fb599d5630a579bacfa8166b928b7e49e3b71280f30f5d9", size = 16296687 }, { url = "https://files.pythonhosted.org/packages/24/ca/c638ff0f49f0d971a1fa459f500abd5ac8d7472491ba1b1b6da95c5c7ea5/uv-0.5.24-py3-none-win32.whl", hash = "sha256:ecb71bcada372274db34bd32f6a9214974b26b6cdc3145a26d07a710f2ea7f18", size = 15430745 }, { url = "https://files.pythonhosted.org/packages/fc/0e/5a2cd5519e78528c99f7fe80514f03bf4bfbd51966bf8b55bd746c6e8675/uv-0.5.24-py3-none-win_amd64.whl", hash = "sha256:9059775b0c74a68799f3e665a08c429f527d3cdf61c15227992cfff75e31c327", size = 16826614 }, ] [[package]] name = "virtualenv" version = "20.29.1" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "distlib" }, { name = "filelock" }, { name = "platformdirs" }, ] sdist = { url = "https://files.pythonhosted.org/packages/a7/ca/f23dcb02e161a9bba141b1c08aa50e8da6ea25e6d780528f1d385a3efe25/virtualenv-20.29.1.tar.gz", hash = "sha256:b8b8970138d32fb606192cb97f6cd4bb644fa486be9308fb9b63f81091b5dc35", size = 7658028 } wheels = [ { url = "https://files.pythonhosted.org/packages/89/9b/599bcfc7064fbe5740919e78c5df18e5dceb0887e676256a1061bb5ae232/virtualenv-20.29.1-py3-none-any.whl", hash = "sha256:4e4cb403c0b0da39e13b46b1b2476e505cb0046b25f242bee80f62bf990b2779", size = 4282379 }, ] [[package]] name = "vulture" version = "2.14" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "tomli", marker = "python_full_version < '3.11'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/8e/25/925f35db758a0f9199113aaf61d703de891676b082bd7cf73ea01d6000f7/vulture-2.14.tar.gz", hash = "sha256:cb8277902a1138deeab796ec5bef7076a6e0248ca3607a3f3dee0b6d9e9b8415", size = 58823 } wheels = [ { url = "https://files.pythonhosted.org/packages/a0/56/0cc15b8ff2613c1d5c3dc1f3f576ede1c43868c1bc2e5ccaa2d4bcd7974d/vulture-2.14-py2.py3-none-any.whl", hash = "sha256:d9a90dba89607489548a49d557f8bac8112bd25d3cbc8aeef23e860811bd5ed9", size = 28915 }, ] [[package]] name = "watchdog" version = "6.0.0" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/db/7d/7f3d619e951c88ed75c6037b246ddcf2d322812ee8ea189be89511721d54/watchdog-6.0.0.tar.gz", hash = "sha256:9ddf7c82fda3ae8e24decda1338ede66e1c99883db93711d8fb941eaa2d8c282", size = 131220 } wheels = [ { url = "https://files.pythonhosted.org/packages/0c/56/90994d789c61df619bfc5ce2ecdabd5eeff564e1eb47512bd01b5e019569/watchdog-6.0.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:d1cdb490583ebd691c012b3d6dae011000fe42edb7a82ece80965b42abd61f26", size = 96390 }, { url = "https://files.pythonhosted.org/packages/55/46/9a67ee697342ddf3c6daa97e3a587a56d6c4052f881ed926a849fcf7371c/watchdog-6.0.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:bc64ab3bdb6a04d69d4023b29422170b74681784ffb9463ed4870cf2f3e66112", size = 88389 }, { url = "https://files.pythonhosted.org/packages/44/65/91b0985747c52064d8701e1075eb96f8c40a79df889e59a399453adfb882/watchdog-6.0.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:c897ac1b55c5a1461e16dae288d22bb2e412ba9807df8397a635d88f671d36c3", size = 89020 }, { url = "https://files.pythonhosted.org/packages/e0/24/d9be5cd6642a6aa68352ded4b4b10fb0d7889cb7f45814fb92cecd35f101/watchdog-6.0.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:6eb11feb5a0d452ee41f824e271ca311a09e250441c262ca2fd7ebcf2461a06c", size = 96393 }, { url = "https://files.pythonhosted.org/packages/63/7a/6013b0d8dbc56adca7fdd4f0beed381c59f6752341b12fa0886fa7afc78b/watchdog-6.0.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:ef810fbf7b781a5a593894e4f439773830bdecb885e6880d957d5b9382a960d2", size = 88392 }, { url = "https://files.pythonhosted.org/packages/d1/40/b75381494851556de56281e053700e46bff5b37bf4c7267e858640af5a7f/watchdog-6.0.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:afd0fe1b2270917c5e23c2a65ce50c2a4abb63daafb0d419fde368e272a76b7c", size = 89019 }, { url = "https://files.pythonhosted.org/packages/39/ea/3930d07dafc9e286ed356a679aa02d777c06e9bfd1164fa7c19c288a5483/watchdog-6.0.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:bdd4e6f14b8b18c334febb9c4425a878a2ac20efd1e0b231978e7b150f92a948", size = 96471 }, { url = "https://files.pythonhosted.org/packages/12/87/48361531f70b1f87928b045df868a9fd4e253d9ae087fa4cf3f7113be363/watchdog-6.0.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:c7c15dda13c4eb00d6fb6fc508b3c0ed88b9d5d374056b239c4ad1611125c860", size = 88449 }, { url = "https://files.pythonhosted.org/packages/5b/7e/8f322f5e600812e6f9a31b75d242631068ca8f4ef0582dd3ae6e72daecc8/watchdog-6.0.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:6f10cb2d5902447c7d0da897e2c6768bca89174d0c6e1e30abec5421af97a5b0", size = 89054 }, { url = "https://files.pythonhosted.org/packages/68/98/b0345cabdce2041a01293ba483333582891a3bd5769b08eceb0d406056ef/watchdog-6.0.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:490ab2ef84f11129844c23fb14ecf30ef3d8a6abafd3754a6f75ca1e6654136c", size = 96480 }, { url = "https://files.pythonhosted.org/packages/85/83/cdf13902c626b28eedef7ec4f10745c52aad8a8fe7eb04ed7b1f111ca20e/watchdog-6.0.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:76aae96b00ae814b181bb25b1b98076d5fc84e8a53cd8885a318b42b6d3a5134", size = 88451 }, { url = "https://files.pythonhosted.org/packages/fe/c4/225c87bae08c8b9ec99030cd48ae9c4eca050a59bf5c2255853e18c87b50/watchdog-6.0.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:a175f755fc2279e0b7312c0035d52e27211a5bc39719dd529625b1930917345b", size = 89057 }, { url = "https://files.pythonhosted.org/packages/05/52/7223011bb760fce8ddc53416beb65b83a3ea6d7d13738dde75eeb2c89679/watchdog-6.0.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:e6f0e77c9417e7cd62af82529b10563db3423625c5fce018430b249bf977f9e8", size = 96390 }, { url = "https://files.pythonhosted.org/packages/9c/62/d2b21bc4e706d3a9d467561f487c2938cbd881c69f3808c43ac1ec242391/watchdog-6.0.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:90c8e78f3b94014f7aaae121e6b909674df5b46ec24d6bebc45c44c56729af2a", size = 88386 }, { url = "https://files.pythonhosted.org/packages/ea/22/1c90b20eda9f4132e4603a26296108728a8bfe9584b006bd05dd94548853/watchdog-6.0.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:e7631a77ffb1f7d2eefa4445ebbee491c720a5661ddf6df3498ebecae5ed375c", size = 89017 }, { url = "https://files.pythonhosted.org/packages/30/ad/d17b5d42e28a8b91f8ed01cb949da092827afb9995d4559fd448d0472763/watchdog-6.0.0-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:c7ac31a19f4545dd92fc25d200694098f42c9a8e391bc00bdd362c5736dbf881", size = 87902 }, { url = "https://files.pythonhosted.org/packages/5c/ca/c3649991d140ff6ab67bfc85ab42b165ead119c9e12211e08089d763ece5/watchdog-6.0.0-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:9513f27a1a582d9808cf21a07dae516f0fab1cf2d7683a742c498b93eedabb11", size = 88380 }, { url = "https://files.pythonhosted.org/packages/5b/79/69f2b0e8d3f2afd462029031baafb1b75d11bb62703f0e1022b2e54d49ee/watchdog-6.0.0-pp39-pypy39_pp73-macosx_10_15_x86_64.whl", hash = "sha256:7a0e56874cfbc4b9b05c60c8a1926fedf56324bb08cfbc188969777940aef3aa", size = 87903 }, { url = "https://files.pythonhosted.org/packages/e2/2b/dc048dd71c2e5f0f7ebc04dd7912981ec45793a03c0dc462438e0591ba5d/watchdog-6.0.0-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:e6439e374fc012255b4ec786ae3c4bc838cd7309a540e5fe0952d03687d8804e", size = 88381 }, { url = "https://files.pythonhosted.org/packages/a9/c7/ca4bf3e518cb57a686b2feb4f55a1892fd9a3dd13f470fca14e00f80ea36/watchdog-6.0.0-py3-none-manylinux2014_aarch64.whl", hash = "sha256:7607498efa04a3542ae3e05e64da8202e58159aa1fa4acddf7678d34a35d4f13", size = 79079 }, { url = "https://files.pythonhosted.org/packages/5c/51/d46dc9332f9a647593c947b4b88e2381c8dfc0942d15b8edc0310fa4abb1/watchdog-6.0.0-py3-none-manylinux2014_armv7l.whl", hash = "sha256:9041567ee8953024c83343288ccc458fd0a2d811d6a0fd68c4c22609e3490379", size = 79078 }, { url = "https://files.pythonhosted.org/packages/d4/57/04edbf5e169cd318d5f07b4766fee38e825d64b6913ca157ca32d1a42267/watchdog-6.0.0-py3-none-manylinux2014_i686.whl", hash = "sha256:82dc3e3143c7e38ec49d61af98d6558288c415eac98486a5c581726e0737c00e", size = 79076 }, { url = "https://files.pythonhosted.org/packages/ab/cc/da8422b300e13cb187d2203f20b9253e91058aaf7db65b74142013478e66/watchdog-6.0.0-py3-none-manylinux2014_ppc64.whl", hash = "sha256:212ac9b8bf1161dc91bd09c048048a95ca3a4c4f5e5d4a7d1b1a7d5752a7f96f", size = 79077 }, { url = "https://files.pythonhosted.org/packages/2c/3b/b8964e04ae1a025c44ba8e4291f86e97fac443bca31de8bd98d3263d2fcf/watchdog-6.0.0-py3-none-manylinux2014_ppc64le.whl", hash = "sha256:e3df4cbb9a450c6d49318f6d14f4bbc80d763fa587ba46ec86f99f9e6876bb26", size = 79078 }, { url = "https://files.pythonhosted.org/packages/62/ae/a696eb424bedff7407801c257d4b1afda455fe40821a2be430e173660e81/watchdog-6.0.0-py3-none-manylinux2014_s390x.whl", hash = "sha256:2cce7cfc2008eb51feb6aab51251fd79b85d9894e98ba847408f662b3395ca3c", size = 79077 }, { url = "https://files.pythonhosted.org/packages/b5/e8/dbf020b4d98251a9860752a094d09a65e1b436ad181faf929983f697048f/watchdog-6.0.0-py3-none-manylinux2014_x86_64.whl", hash = "sha256:20ffe5b202af80ab4266dcd3e91aae72bf2da48c0d33bdb15c66658e685e94e2", size = 79078 }, { url = "https://files.pythonhosted.org/packages/07/f6/d0e5b343768e8bcb4cda79f0f2f55051bf26177ecd5651f84c07567461cf/watchdog-6.0.0-py3-none-win32.whl", hash = "sha256:07df1fdd701c5d4c8e55ef6cf55b8f0120fe1aef7ef39a1c6fc6bc2e606d517a", size = 79065 }, { url = "https://files.pythonhosted.org/packages/db/d9/c495884c6e548fce18a8f40568ff120bc3a4b7b99813081c8ac0c936fa64/watchdog-6.0.0-py3-none-win_amd64.whl", hash = "sha256:cbafb470cf848d93b5d013e2ecb245d4aa1c8fd0504e863ccefa32445359d680", size = 79070 }, { url = "https://files.pythonhosted.org/packages/33/e8/e40370e6d74ddba47f002a32919d91310d6074130fe4e17dabcafc15cbf1/watchdog-6.0.0-py3-none-win_ia64.whl", hash = "sha256:a1914259fa9e1454315171103c6a30961236f508b9b623eae470268bbcc6a22f", size = 79067 }, ] [[package]] name = "wcwidth" version = "0.2.13" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/6c/63/53559446a878410fc5a5974feb13d31d78d752eb18aeba59c7fef1af7598/wcwidth-0.2.13.tar.gz", hash = "sha256:72ea0c06399eb286d978fdedb6923a9eb47e1c486ce63e9b4e64fc18303972b5", size = 101301 } wheels = [ { url = "https://files.pythonhosted.org/packages/fd/84/fd2ba7aafacbad3c4201d395674fc6348826569da3c0937e75505ead3528/wcwidth-0.2.13-py2.py3-none-any.whl", hash = "sha256:3da69048e4540d84af32131829ff948f1e022c1c6bdb8d6102117aac784f6859", size = 34166 }, ] [[package]] name = "webencodings" version = "0.5.1" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/0b/02/ae6ceac1baeda530866a85075641cec12989bd8d31af6d5ab4a3e8c92f47/webencodings-0.5.1.tar.gz", hash = "sha256:b36a1c245f2d304965eb4e0a82848379241dc04b865afcc4aab16748587e1923", size = 9721 } wheels = [ { url = "https://files.pythonhosted.org/packages/f4/24/2a3e3df732393fed8b3ebf2ec078f05546de641fe1b667ee316ec1dcf3b7/webencodings-0.5.1-py2.py3-none-any.whl", hash = "sha256:a0af1213f3c2226497a97e2b3aa01a7e4bee4f403f95be16fc9acd2947514a78", size = 11774 }, ] [[package]] name = "yarg" version = "0.1.9" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "requests" }, ] sdist = { url = "https://files.pythonhosted.org/packages/d4/c8/cc640404a0981e6c14e2044fc64e43b4c1ddf69e7dddc8f2a02638ba5ae8/yarg-0.1.9.tar.gz", hash = "sha256:55695bf4d1e3e7f756496c36a69ba32c40d18f821e38f61d028f6049e5e15911", size = 11988 } wheels = [ { url = "https://files.pythonhosted.org/packages/8b/90/89a2ff242ccab6a24fbab18dbbabc67c51a6f0ed01f9a0f41689dc177419/yarg-0.1.9-py2.py3-none-any.whl", hash = "sha256:4f9cebdc00fac946c9bf2783d634e538a71c7d280a4d806d45fd4dc0ef441492", size = 19162 }, ] [[package]] name = "yaspin" version = "2.5.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "termcolor" }, ] sdist = { url = "https://files.pythonhosted.org/packages/77/40/5232871d34d726b125a2a890e8b4531800858fee95779b14d53b26f4143e/yaspin-2.5.0.tar.gz", hash = "sha256:f96ab3b5c42e1eaa6af3193508082309d9dc43f6963339f9aa606003ee8d7e63", size = 34589 } wheels = [ { url = "https://files.pythonhosted.org/packages/67/4b/6873fb66cefc5bdb44cc0625d81fcf8eb49f331d0f9dced9f5a0f803dd3f/yaspin-2.5.0-py3-none-any.whl", hash = "sha256:58aaa19330b9eacf86241043342b4040ded75f170240276d963c570263cd8f53", size = 18959 }, ] [[package]] name = "zipp" version = "3.21.0" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/3f/50/bad581df71744867e9468ebd0bcd6505de3b275e06f202c2cb016e3ff56f/zipp-3.21.0.tar.gz", hash = "sha256:2c9958f6430a2040341a52eb608ed6dd93ef4392e02ffe219417c1b28b5dd1f4", size = 24545 } wheels = [ { url = "https://files.pythonhosted.org/packages/b7/1a/7e4798e9339adc931158c9d69ecc34f5e6791489d469f5e50ec15e35f458/zipp-3.21.0-py3-none-any.whl", hash = "sha256:ac1bbe05fd2991f160ebce24ffbac5f6d11d83dc90891255885223d42b3cd931", size = 9630 }, ] [[package]] name = "zstandard" version = "0.23.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "cffi", marker = "platform_python_implementation == 'PyPy'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/ed/f6/2ac0287b442160a89d726b17a9184a4c615bb5237db763791a7fd16d9df1/zstandard-0.23.0.tar.gz", hash = "sha256:b2d8c62d08e7255f68f7a740bae85b3c9b8e5466baa9cbf7f57f1cde0ac6bc09", size = 681701 } wheels = [ { url = "https://files.pythonhosted.org/packages/2a/55/bd0487e86679db1823fc9ee0d8c9c78ae2413d34c0b461193b5f4c31d22f/zstandard-0.23.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:bf0a05b6059c0528477fba9054d09179beb63744355cab9f38059548fedd46a9", size = 788701 }, { url = "https://files.pythonhosted.org/packages/e1/8a/ccb516b684f3ad987dfee27570d635822e3038645b1a950c5e8022df1145/zstandard-0.23.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:fc9ca1c9718cb3b06634c7c8dec57d24e9438b2aa9a0f02b8bb36bf478538880", size = 633678 }, { url = "https://files.pythonhosted.org/packages/12/89/75e633d0611c028e0d9af6df199423bf43f54bea5007e6718ab7132e234c/zstandard-0.23.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:77da4c6bfa20dd5ea25cbf12c76f181a8e8cd7ea231c673828d0386b1740b8dc", size = 4941098 }, { url = "https://files.pythonhosted.org/packages/4a/7a/bd7f6a21802de358b63f1ee636ab823711c25ce043a3e9f043b4fcb5ba32/zstandard-0.23.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b2170c7e0367dde86a2647ed5b6f57394ea7f53545746104c6b09fc1f4223573", size = 5308798 }, { url = "https://files.pythonhosted.org/packages/79/3b/775f851a4a65013e88ca559c8ae42ac1352db6fcd96b028d0df4d7d1d7b4/zstandard-0.23.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c16842b846a8d2a145223f520b7e18b57c8f476924bda92aeee3a88d11cfc391", size = 5341840 }, { url = "https://files.pythonhosted.org/packages/09/4f/0cc49570141dd72d4d95dd6fcf09328d1b702c47a6ec12fbed3b8aed18a5/zstandard-0.23.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:157e89ceb4054029a289fb504c98c6a9fe8010f1680de0201b3eb5dc20aa6d9e", size = 5440337 }, { url = "https://files.pythonhosted.org/packages/e7/7c/aaa7cd27148bae2dc095191529c0570d16058c54c4597a7d118de4b21676/zstandard-0.23.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:203d236f4c94cd8379d1ea61db2fce20730b4c38d7f1c34506a31b34edc87bdd", size = 4861182 }, { url = "https://files.pythonhosted.org/packages/ac/eb/4b58b5c071d177f7dc027129d20bd2a44161faca6592a67f8fcb0b88b3ae/zstandard-0.23.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:dc5d1a49d3f8262be192589a4b72f0d03b72dcf46c51ad5852a4fdc67be7b9e4", size = 4932936 }, { url = "https://files.pythonhosted.org/packages/44/f9/21a5fb9bb7c9a274b05ad700a82ad22ce82f7ef0f485980a1e98ed6e8c5f/zstandard-0.23.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:752bf8a74412b9892f4e5b58f2f890a039f57037f52c89a740757ebd807f33ea", size = 5464705 }, { url = "https://files.pythonhosted.org/packages/49/74/b7b3e61db3f88632776b78b1db597af3f44c91ce17d533e14a25ce6a2816/zstandard-0.23.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:80080816b4f52a9d886e67f1f96912891074903238fe54f2de8b786f86baded2", size = 4857882 }, { url = "https://files.pythonhosted.org/packages/4a/7f/d8eb1cb123d8e4c541d4465167080bec88481ab54cd0b31eb4013ba04b95/zstandard-0.23.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:84433dddea68571a6d6bd4fbf8ff398236031149116a7fff6f777ff95cad3df9", size = 4697672 }, { url = "https://files.pythonhosted.org/packages/5e/05/f7dccdf3d121309b60342da454d3e706453a31073e2c4dac8e1581861e44/zstandard-0.23.0-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:ab19a2d91963ed9e42b4e8d77cd847ae8381576585bad79dbd0a8837a9f6620a", size = 5206043 }, { url = "https://files.pythonhosted.org/packages/86/9d/3677a02e172dccd8dd3a941307621c0cbd7691d77cb435ac3c75ab6a3105/zstandard-0.23.0-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:59556bf80a7094d0cfb9f5e50bb2db27fefb75d5138bb16fb052b61b0e0eeeb0", size = 5667390 }, { url = "https://files.pythonhosted.org/packages/41/7e/0012a02458e74a7ba122cd9cafe491facc602c9a17f590367da369929498/zstandard-0.23.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:27d3ef2252d2e62476389ca8f9b0cf2bbafb082a3b6bfe9d90cbcbb5529ecf7c", size = 5198901 }, { url = "https://files.pythonhosted.org/packages/65/3a/8f715b97bd7bcfc7342d8adcd99a026cb2fb550e44866a3b6c348e1b0f02/zstandard-0.23.0-cp310-cp310-win32.whl", hash = "sha256:5d41d5e025f1e0bccae4928981e71b2334c60f580bdc8345f824e7c0a4c2a813", size = 430596 }, { url = "https://files.pythonhosted.org/packages/19/b7/b2b9eca5e5a01111e4fe8a8ffb56bdcdf56b12448a24effe6cfe4a252034/zstandard-0.23.0-cp310-cp310-win_amd64.whl", hash = "sha256:519fbf169dfac1222a76ba8861ef4ac7f0530c35dd79ba5727014613f91613d4", size = 495498 }, { url = "https://files.pythonhosted.org/packages/9e/40/f67e7d2c25a0e2dc1744dd781110b0b60306657f8696cafb7ad7579469bd/zstandard-0.23.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:34895a41273ad33347b2fc70e1bff4240556de3c46c6ea430a7ed91f9042aa4e", size = 788699 }, { url = "https://files.pythonhosted.org/packages/e8/46/66d5b55f4d737dd6ab75851b224abf0afe5774976fe511a54d2eb9063a41/zstandard-0.23.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:77ea385f7dd5b5676d7fd943292ffa18fbf5c72ba98f7d09fc1fb9e819b34c23", size = 633681 }, { url = "https://files.pythonhosted.org/packages/63/b6/677e65c095d8e12b66b8f862b069bcf1f1d781b9c9c6f12eb55000d57583/zstandard-0.23.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:983b6efd649723474f29ed42e1467f90a35a74793437d0bc64a5bf482bedfa0a", size = 4944328 }, { url = "https://files.pythonhosted.org/packages/59/cc/e76acb4c42afa05a9d20827116d1f9287e9c32b7ad58cc3af0721ce2b481/zstandard-0.23.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:80a539906390591dd39ebb8d773771dc4db82ace6372c4d41e2d293f8e32b8db", size = 5311955 }, { url = "https://files.pythonhosted.org/packages/78/e4/644b8075f18fc7f632130c32e8f36f6dc1b93065bf2dd87f03223b187f26/zstandard-0.23.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:445e4cb5048b04e90ce96a79b4b63140e3f4ab5f662321975679b5f6360b90e2", size = 5344944 }, { url = "https://files.pythonhosted.org/packages/76/3f/dbafccf19cfeca25bbabf6f2dd81796b7218f768ec400f043edc767015a6/zstandard-0.23.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fd30d9c67d13d891f2360b2a120186729c111238ac63b43dbd37a5a40670b8ca", size = 5442927 }, { url = "https://files.pythonhosted.org/packages/0c/c3/d24a01a19b6733b9f218e94d1a87c477d523237e07f94899e1c10f6fd06c/zstandard-0.23.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d20fd853fbb5807c8e84c136c278827b6167ded66c72ec6f9a14b863d809211c", size = 4864910 }, { url = "https://files.pythonhosted.org/packages/1c/a9/cf8f78ead4597264f7618d0875be01f9bc23c9d1d11afb6d225b867cb423/zstandard-0.23.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:ed1708dbf4d2e3a1c5c69110ba2b4eb6678262028afd6c6fbcc5a8dac9cda68e", size = 4935544 }, { url = "https://files.pythonhosted.org/packages/2c/96/8af1e3731b67965fb995a940c04a2c20997a7b3b14826b9d1301cf160879/zstandard-0.23.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:be9b5b8659dff1f913039c2feee1aca499cfbc19e98fa12bc85e037c17ec6ca5", size = 5467094 }, { url = "https://files.pythonhosted.org/packages/ff/57/43ea9df642c636cb79f88a13ab07d92d88d3bfe3e550b55a25a07a26d878/zstandard-0.23.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:65308f4b4890aa12d9b6ad9f2844b7ee42c7f7a4fd3390425b242ffc57498f48", size = 4860440 }, { url = "https://files.pythonhosted.org/packages/46/37/edb78f33c7f44f806525f27baa300341918fd4c4af9472fbc2c3094be2e8/zstandard-0.23.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:98da17ce9cbf3bfe4617e836d561e433f871129e3a7ac16d6ef4c680f13a839c", size = 4700091 }, { url = "https://files.pythonhosted.org/packages/c1/f1/454ac3962671a754f3cb49242472df5c2cced4eb959ae203a377b45b1a3c/zstandard-0.23.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:8ed7d27cb56b3e058d3cf684d7200703bcae623e1dcc06ed1e18ecda39fee003", size = 5208682 }, { url = "https://files.pythonhosted.org/packages/85/b2/1734b0fff1634390b1b887202d557d2dd542de84a4c155c258cf75da4773/zstandard-0.23.0-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:b69bb4f51daf461b15e7b3db033160937d3ff88303a7bc808c67bbc1eaf98c78", size = 5669707 }, { url = "https://files.pythonhosted.org/packages/52/5a/87d6971f0997c4b9b09c495bf92189fb63de86a83cadc4977dc19735f652/zstandard-0.23.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:034b88913ecc1b097f528e42b539453fa82c3557e414b3de9d5632c80439a473", size = 5201792 }, { url = "https://files.pythonhosted.org/packages/79/02/6f6a42cc84459d399bd1a4e1adfc78d4dfe45e56d05b072008d10040e13b/zstandard-0.23.0-cp311-cp311-win32.whl", hash = "sha256:f2d4380bf5f62daabd7b751ea2339c1a21d1c9463f1feb7fc2bdcea2c29c3160", size = 430586 }, { url = "https://files.pythonhosted.org/packages/be/a2/4272175d47c623ff78196f3c10e9dc7045c1b9caf3735bf041e65271eca4/zstandard-0.23.0-cp311-cp311-win_amd64.whl", hash = "sha256:62136da96a973bd2557f06ddd4e8e807f9e13cbb0bfb9cc06cfe6d98ea90dfe0", size = 495420 }, { url = "https://files.pythonhosted.org/packages/7b/83/f23338c963bd9de687d47bf32efe9fd30164e722ba27fb59df33e6b1719b/zstandard-0.23.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:b4567955a6bc1b20e9c31612e615af6b53733491aeaa19a6b3b37f3b65477094", size = 788713 }, { url = "https://files.pythonhosted.org/packages/5b/b3/1a028f6750fd9227ee0b937a278a434ab7f7fdc3066c3173f64366fe2466/zstandard-0.23.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:1e172f57cd78c20f13a3415cc8dfe24bf388614324d25539146594c16d78fcc8", size = 633459 }, { url = "https://files.pythonhosted.org/packages/26/af/36d89aae0c1f95a0a98e50711bc5d92c144939efc1f81a2fcd3e78d7f4c1/zstandard-0.23.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b0e166f698c5a3e914947388c162be2583e0c638a4703fc6a543e23a88dea3c1", size = 4945707 }, { url = "https://files.pythonhosted.org/packages/cd/2e/2051f5c772f4dfc0aae3741d5fc72c3dcfe3aaeb461cc231668a4db1ce14/zstandard-0.23.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:12a289832e520c6bd4dcaad68e944b86da3bad0d339ef7989fb7e88f92e96072", size = 5306545 }, { url = "https://files.pythonhosted.org/packages/0a/9e/a11c97b087f89cab030fa71206963090d2fecd8eb83e67bb8f3ffb84c024/zstandard-0.23.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d50d31bfedd53a928fed6707b15a8dbeef011bb6366297cc435accc888b27c20", size = 5337533 }, { url = "https://files.pythonhosted.org/packages/fc/79/edeb217c57fe1bf16d890aa91a1c2c96b28c07b46afed54a5dcf310c3f6f/zstandard-0.23.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:72c68dda124a1a138340fb62fa21b9bf4848437d9ca60bd35db36f2d3345f373", size = 5436510 }, { url = "https://files.pythonhosted.org/packages/81/4f/c21383d97cb7a422ddf1ae824b53ce4b51063d0eeb2afa757eb40804a8ef/zstandard-0.23.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:53dd9d5e3d29f95acd5de6802e909ada8d8d8cfa37a3ac64836f3bc4bc5512db", size = 4859973 }, { url = "https://files.pythonhosted.org/packages/ab/15/08d22e87753304405ccac8be2493a495f529edd81d39a0870621462276ef/zstandard-0.23.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:6a41c120c3dbc0d81a8e8adc73312d668cd34acd7725f036992b1b72d22c1772", size = 4936968 }, { url = "https://files.pythonhosted.org/packages/eb/fa/f3670a597949fe7dcf38119a39f7da49a8a84a6f0b1a2e46b2f71a0ab83f/zstandard-0.23.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:40b33d93c6eddf02d2c19f5773196068d875c41ca25730e8288e9b672897c105", size = 5467179 }, { url = "https://files.pythonhosted.org/packages/4e/a9/dad2ab22020211e380adc477a1dbf9f109b1f8d94c614944843e20dc2a99/zstandard-0.23.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:9206649ec587e6b02bd124fb7799b86cddec350f6f6c14bc82a2b70183e708ba", size = 4848577 }, { url = "https://files.pythonhosted.org/packages/08/03/dd28b4484b0770f1e23478413e01bee476ae8227bbc81561f9c329e12564/zstandard-0.23.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:76e79bc28a65f467e0409098fa2c4376931fd3207fbeb6b956c7c476d53746dd", size = 4693899 }, { url = "https://files.pythonhosted.org/packages/2b/64/3da7497eb635d025841e958bcd66a86117ae320c3b14b0ae86e9e8627518/zstandard-0.23.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:66b689c107857eceabf2cf3d3fc699c3c0fe8ccd18df2219d978c0283e4c508a", size = 5199964 }, { url = "https://files.pythonhosted.org/packages/43/a4/d82decbab158a0e8a6ebb7fc98bc4d903266bce85b6e9aaedea1d288338c/zstandard-0.23.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:9c236e635582742fee16603042553d276cca506e824fa2e6489db04039521e90", size = 5655398 }, { url = "https://files.pythonhosted.org/packages/f2/61/ac78a1263bc83a5cf29e7458b77a568eda5a8f81980691bbc6eb6a0d45cc/zstandard-0.23.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:a8fffdbd9d1408006baaf02f1068d7dd1f016c6bcb7538682622c556e7b68e35", size = 5191313 }, { url = "https://files.pythonhosted.org/packages/e7/54/967c478314e16af5baf849b6ee9d6ea724ae5b100eb506011f045d3d4e16/zstandard-0.23.0-cp312-cp312-win32.whl", hash = "sha256:dc1d33abb8a0d754ea4763bad944fd965d3d95b5baef6b121c0c9013eaf1907d", size = 430877 }, { url = "https://files.pythonhosted.org/packages/75/37/872d74bd7739639c4553bf94c84af7d54d8211b626b352bc57f0fd8d1e3f/zstandard-0.23.0-cp312-cp312-win_amd64.whl", hash = "sha256:64585e1dba664dc67c7cdabd56c1e5685233fbb1fc1966cfba2a340ec0dfff7b", size = 495595 }, { url = "https://files.pythonhosted.org/packages/80/f1/8386f3f7c10261fe85fbc2c012fdb3d4db793b921c9abcc995d8da1b7a80/zstandard-0.23.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:576856e8594e6649aee06ddbfc738fec6a834f7c85bf7cadd1c53d4a58186ef9", size = 788975 }, { url = "https://files.pythonhosted.org/packages/16/e8/cbf01077550b3e5dc86089035ff8f6fbbb312bc0983757c2d1117ebba242/zstandard-0.23.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:38302b78a850ff82656beaddeb0bb989a0322a8bbb1bf1ab10c17506681d772a", size = 633448 }, { url = "https://files.pythonhosted.org/packages/06/27/4a1b4c267c29a464a161aeb2589aff212b4db653a1d96bffe3598f3f0d22/zstandard-0.23.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d2240ddc86b74966c34554c49d00eaafa8200a18d3a5b6ffbf7da63b11d74ee2", size = 4945269 }, { url = "https://files.pythonhosted.org/packages/7c/64/d99261cc57afd9ae65b707e38045ed8269fbdae73544fd2e4a4d50d0ed83/zstandard-0.23.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2ef230a8fd217a2015bc91b74f6b3b7d6522ba48be29ad4ea0ca3a3775bf7dd5", size = 5306228 }, { url = "https://files.pythonhosted.org/packages/7a/cf/27b74c6f22541f0263016a0fd6369b1b7818941de639215c84e4e94b2a1c/zstandard-0.23.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:774d45b1fac1461f48698a9d4b5fa19a69d47ece02fa469825b442263f04021f", size = 5336891 }, { url = "https://files.pythonhosted.org/packages/fa/18/89ac62eac46b69948bf35fcd90d37103f38722968e2981f752d69081ec4d/zstandard-0.23.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6f77fa49079891a4aab203d0b1744acc85577ed16d767b52fc089d83faf8d8ed", size = 5436310 }, { url = "https://files.pythonhosted.org/packages/a8/a8/5ca5328ee568a873f5118d5b5f70d1f36c6387716efe2e369010289a5738/zstandard-0.23.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ac184f87ff521f4840e6ea0b10c0ec90c6b1dcd0bad2f1e4a9a1b4fa177982ea", size = 4859912 }, { url = "https://files.pythonhosted.org/packages/ea/ca/3781059c95fd0868658b1cf0440edd832b942f84ae60685d0cfdb808bca1/zstandard-0.23.0-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:c363b53e257246a954ebc7c488304b5592b9c53fbe74d03bc1c64dda153fb847", size = 4936946 }, { url = "https://files.pythonhosted.org/packages/ce/11/41a58986f809532742c2b832c53b74ba0e0a5dae7e8ab4642bf5876f35de/zstandard-0.23.0-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:e7792606d606c8df5277c32ccb58f29b9b8603bf83b48639b7aedf6df4fe8171", size = 5466994 }, { url = "https://files.pythonhosted.org/packages/83/e3/97d84fe95edd38d7053af05159465d298c8b20cebe9ccb3d26783faa9094/zstandard-0.23.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:a0817825b900fcd43ac5d05b8b3079937073d2b1ff9cf89427590718b70dd840", size = 4848681 }, { url = "https://files.pythonhosted.org/packages/6e/99/cb1e63e931de15c88af26085e3f2d9af9ce53ccafac73b6e48418fd5a6e6/zstandard-0.23.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:9da6bc32faac9a293ddfdcb9108d4b20416219461e4ec64dfea8383cac186690", size = 4694239 }, { url = "https://files.pythonhosted.org/packages/ab/50/b1e703016eebbc6501fc92f34db7b1c68e54e567ef39e6e59cf5fb6f2ec0/zstandard-0.23.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:fd7699e8fd9969f455ef2926221e0233f81a2542921471382e77a9e2f2b57f4b", size = 5200149 }, { url = "https://files.pythonhosted.org/packages/aa/e0/932388630aaba70197c78bdb10cce2c91fae01a7e553b76ce85471aec690/zstandard-0.23.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:d477ed829077cd945b01fc3115edd132c47e6540ddcd96ca169facff28173057", size = 5655392 }, { url = "https://files.pythonhosted.org/packages/02/90/2633473864f67a15526324b007a9f96c96f56d5f32ef2a56cc12f9548723/zstandard-0.23.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:fa6ce8b52c5987b3e34d5674b0ab529a4602b632ebab0a93b07bfb4dfc8f8a33", size = 5191299 }, { url = "https://files.pythonhosted.org/packages/b0/4c/315ca5c32da7e2dc3455f3b2caee5c8c2246074a61aac6ec3378a97b7136/zstandard-0.23.0-cp313-cp313-win32.whl", hash = "sha256:a9b07268d0c3ca5c170a385a0ab9fb7fdd9f5fd866be004c4ea39e44edce47dd", size = 430862 }, { url = "https://files.pythonhosted.org/packages/a2/bf/c6aaba098e2d04781e8f4f7c0ba3c7aa73d00e4c436bcc0cf059a66691d1/zstandard-0.23.0-cp313-cp313-win_amd64.whl", hash = "sha256:f3513916e8c645d0610815c257cbfd3242adfd5c4cfa78be514e5a3ebb42a41b", size = 495578 }, { url = "https://files.pythonhosted.org/packages/fb/96/4fcafeb7e013a2386d22f974b5b97a0b9a65004ed58c87ae001599bfbd48/zstandard-0.23.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:3aa014d55c3af933c1315eb4bb06dd0459661cc0b15cd61077afa6489bec63bb", size = 788697 }, { url = "https://files.pythonhosted.org/packages/83/ff/a52ce725be69b86a2967ecba0497a8184540cc284c0991125515449e54e2/zstandard-0.23.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:0a7f0804bb3799414af278e9ad51be25edf67f78f916e08afdb983e74161b916", size = 633679 }, { url = "https://files.pythonhosted.org/packages/34/0f/3dc62db122f6a9c481c335fff6fc9f4e88d8f6e2d47321ee3937328addb4/zstandard-0.23.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fb2b1ecfef1e67897d336de3a0e3f52478182d6a47eda86cbd42504c5cbd009a", size = 4940416 }, { url = "https://files.pythonhosted.org/packages/1d/e5/9fe0dd8c85fdc2f635e6660d07872a5dc4b366db566630161e39f9f804e1/zstandard-0.23.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:837bb6764be6919963ef41235fd56a6486b132ea64afe5fafb4cb279ac44f259", size = 5307693 }, { url = "https://files.pythonhosted.org/packages/73/bf/fe62c0cd865c171ee8ed5bc83174b5382a2cb729c8d6162edfb99a83158b/zstandard-0.23.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1516c8c37d3a053b01c1c15b182f3b5f5eef19ced9b930b684a73bad121addf4", size = 5341236 }, { url = "https://files.pythonhosted.org/packages/39/86/4fe79b30c794286110802a6cd44a73b6a314ac8196b9338c0fbd78c2407d/zstandard-0.23.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:48ef6a43b1846f6025dde6ed9fee0c24e1149c1c25f7fb0a0585572b2f3adc58", size = 5439101 }, { url = "https://files.pythonhosted.org/packages/72/ed/cacec235c581ebf8c608c7fb3d4b6b70d1b490d0e5128ea6996f809ecaef/zstandard-0.23.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:11e3bf3c924853a2d5835b24f03eeba7fc9b07d8ca499e247e06ff5676461a15", size = 4860320 }, { url = "https://files.pythonhosted.org/packages/f6/1e/2c589a2930f93946b132fc852c574a19d5edc23fad2b9e566f431050c7ec/zstandard-0.23.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:2fb4535137de7e244c230e24f9d1ec194f61721c86ebea04e1581d9d06ea1269", size = 4931933 }, { url = "https://files.pythonhosted.org/packages/8e/f5/30eadde3686d902b5d4692bb5f286977cbc4adc082145eb3f49d834b2eae/zstandard-0.23.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:8c24f21fa2af4bb9f2c492a86fe0c34e6d2c63812a839590edaf177b7398f700", size = 5463878 }, { url = "https://files.pythonhosted.org/packages/e0/c8/8aed1f0ab9854ef48e5ad4431367fcb23ce73f0304f7b72335a8edc66556/zstandard-0.23.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:a8c86881813a78a6f4508ef9daf9d4995b8ac2d147dcb1a450448941398091c9", size = 4857192 }, { url = "https://files.pythonhosted.org/packages/a8/c6/55e666cfbcd032b9e271865e8578fec56e5594d4faeac379d371526514f5/zstandard-0.23.0-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:fe3b385d996ee0822fd46528d9f0443b880d4d05528fd26a9119a54ec3f91c69", size = 4696513 }, { url = "https://files.pythonhosted.org/packages/dc/bd/720b65bea63ec9de0ac7414c33b9baf271c8de8996e5ff324dc93fc90ff1/zstandard-0.23.0-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:82d17e94d735c99621bf8ebf9995f870a6b3e6d14543b99e201ae046dfe7de70", size = 5204823 }, { url = "https://files.pythonhosted.org/packages/d8/40/d678db1556e3941d330cd4e95623a63ef235b18547da98fa184cbc028ecf/zstandard-0.23.0-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:c7c517d74bea1a6afd39aa612fa025e6b8011982a0897768a2f7c8ab4ebb78a2", size = 5666490 }, { url = "https://files.pythonhosted.org/packages/ed/cc/c89329723d7515898a1fc7ef5d251264078548c505719d13e9511800a103/zstandard-0.23.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:1fd7e0f1cfb70eb2f95a19b472ee7ad6d9a0a992ec0ae53286870c104ca939e5", size = 5196622 }, { url = "https://files.pythonhosted.org/packages/78/4c/634289d41e094327a94500dfc919e58841b10ea3a9efdfafbac614797ec2/zstandard-0.23.0-cp39-cp39-win32.whl", hash = "sha256:43da0f0092281bf501f9c5f6f3b4c975a8a0ea82de49ba3f7100e64d422a1274", size = 430620 }, { url = "https://files.pythonhosted.org/packages/a2/e2/0b0c5a0f4f7699fecd92c1ba6278ef9b01f2b0b0dd46f62bfc6729c05659/zstandard-0.23.0-cp39-cp39-win_amd64.whl", hash = "sha256:f8346bfa098532bc1fb6c7ef06783e969d87a99dd1d2a5a18a892c1d7a643c58", size = 495528 }, ] isort-6.0.1/.github/FUNDING.yml0000644000000000000000000000006013615410400012747 0ustar00github: "timothycrosley" tidelift: "pypi/isort" isort-6.0.1/.github/dependabot.yml0000644000000000000000000000047613615410400013775 0ustar00# https://docs.github.com/en/code-security/dependabot/dependabot-version-updates/configuration-options-for-the-dependabot.yml-file version: 2 updates: - package-ecosystem: "github-actions" directory: "/" schedule: interval: "monthly" groups: github-actions: patterns: - "*" isort-6.0.1/.github/labels.yml0000644000000000000000000000361313615410400013126 0ustar00--- # Labels names are important as they are used by Release Drafter to decide # regarding where to record them in changelog or if to skip them. # # The repository labels will be automatically configured using this file and # the GitHub Action https://github.com/marketplace/actions/github-labeler. - name: breaking description: Breaking Changes color: "bfd4f2" - name: bug description: Something isn't working color: "d73a4a" - name: build description: Build System and Dependencies color: "bfdadc" - name: ci description: Continuous Integration color: "4a97d6" - name: dependencies description: Pull requests that update a dependency file color: "0366d6" - name: documentation description: Improvements or additions to documentation color: "0075ca" - name: duplicate description: This issue or pull request already exists color: "cfd3d7" - name: enhancement description: New feature or request color: "a2eeef" - name: github_actions description: Pull requests that update Github_actions code color: "000000" - name: good first issue description: Good for newcomers color: "7057ff" - name: help wanted description: Extra attention is needed color: "008672" - name: invalid description: This doesn't seem right color: "e4e669" - name: performance description: Performance color: "016175" - name: python description: Pull requests that update Python code color: "2b67c6" - name: question description: Further information is requested color: "d876e3" - name: refactoring description: Refactoring color: "ef67c4" - name: removal description: Removals and deprecations color: "9ae7ea" - name: style description: Style color: "c120e5" - name: testing description: Testing color: "b1fc6f" - name: wontfix description: This will not be worked on color: "ffffff" - name: skip-changelog description: This will not be added to release notes color: "dddddd" isort-6.0.1/.github/release-drafter.yml0000644000000000000000000000150413615410400014726 0ustar00--- template: | ## Changes $CHANGES categories: - title: ":boom: Breaking Changes" label: "breaking" - title: ":rocket: Features" label: "enhancement" - title: ":fire: Removals and Deprecations" label: "removal" - title: ":beetle: Fixes" label: "bug" - title: ":raising_hand: Help wanted" label: "help wanted" - title: ":racehorse: Performance" label: "performance" - title: ":rotating_light: Testing" label: "testing" - title: ":construction_worker: Continuous Integration" label: "ci" - title: ":books: Documentation" label: "documentation" - title: ":hammer: Refactoring" label: "refactoring" - title: ":lipstick: Style" label: "style" - title: ":package: Dependencies" labels: - "dependencies" - "build" exclude-labels: - "skip-changelog" isort-6.0.1/.github/workflows/integration.yml0000644000000000000000000000125713615410400016246 0ustar00--- name: Integration "on": push: pull_request: permissions: contents: read jobs: build: runs-on: ubuntu-latest strategy: matrix: python-version: ["3.12"] steps: - uses: actions/checkout@v4 - name: Set up Python ${{ matrix.python-version }} uses: actions/setup-python@v5 with: python-version: ${{ matrix.python-version }} - name: Install UV uses: astral-sh/setup-uv@v5 with: enable-cache: true version: ">=0.6.0" - name: Install dependencies run: uv sync --all-extras --frozen - name: Test integration run: ./scripts/test_integration.sh isort-6.0.1/.github/workflows/labeler.yml0000644000000000000000000000046513615410400015331 0ustar00--- name: Labeler "on": push: branches: - main jobs: labeler: runs-on: ubuntu-latest steps: - name: Check out the repository uses: actions/checkout@v4 - name: Run Labeler uses: crazy-max/ghaction-github-labeler@v5 with: skip-delete: true isort-6.0.1/.github/workflows/lint.yml0000644000000000000000000000122013615410400014657 0ustar00--- name: Lint "on": push: pull_request: permissions: contents: read jobs: build: runs-on: ubuntu-latest strategy: matrix: python-version: ["3.12"] steps: - uses: actions/checkout@v4 - name: Set up Python ${{ matrix.python-version }} uses: actions/setup-python@v5 with: python-version: ${{ matrix.python-version }} - name: Install UV uses: astral-sh/setup-uv@v5 with: enable-cache: true version: ">=0.6.0" - name: Install dependencies run: uv sync --all-extras --frozen - name: Lint run: ./scripts/lint.sh isort-6.0.1/.github/workflows/release-dev.yml0000644000000000000000000000107713615410400016117 0ustar00--- name: Release Dev "on": push: branches: - main jobs: release: if: github.repository_owner == 'PyCQA' name: Release runs-on: ubuntu-latest steps: - name: Check out the repository uses: actions/checkout@v4 with: fetch-depth: 2 - name: Set up Python uses: actions/setup-python@v5 with: python-version: "3.13" - name: Install UV uses: astral-sh/setup-uv@v5 with: version: ">=0.6.0" - name: Build package run: | uv build isort-6.0.1/.github/workflows/release-drafter.yml0000644000000000000000000000043713615410400016767 0ustar00--- name: Release Drafter "on": push: branches: - main jobs: draft_release: if: github.repository_owner == 'PyCQA' runs-on: ubuntu-latest steps: - uses: release-drafter/release-drafter@v6 env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} isort-6.0.1/.github/workflows/release.yml0000644000000000000000000000256313615410400015344 0ustar00--- name: Release "on": push: tags: - "[0-9]+.[0-9]+.[0-9]+" jobs: release: if: github.repository_owner == 'PyCQA' name: Release runs-on: ubuntu-latest steps: - name: Check out the repository uses: actions/checkout@v4 with: fetch-depth: 2 - name: Set Tag env run: echo "RELEASE_VERSION=${GITHUB_REF#refs/*/}" >> $GITHUB_ENV - name: Set up Python uses: actions/setup-python@v5 with: python-version: "3.13" - name: Install UV uses: astral-sh/setup-uv@v5 with: version: ">=0.6.0" - name: Install dependencies run: | uv sync --all-extras --frozen - name: Check if there is a parent commit id: check-parent-commit run: | echo "::set-output name=sha::$(git rev-parse --verify --quiet HEAD^)" - name: Build package run: | uv build - name: Publish package on PyPI uses: pypa/gh-action-pypi-publish@release/v1 with: password: ${{ secrets.PYPI_API_TOKEN }} - name: Publish the release notes uses: release-drafter/release-drafter@v6 with: publish: ${{ steps.check-version.outputs.tag != '' }} tag: ${{ steps.check-version.outputs.tag }} env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} isort-6.0.1/.github/workflows/test.yml0000644000000000000000000000167713615410400014710 0ustar00--- name: Test on: push: pull_request: permissions: contents: read env: FORCE_COLOR: 1 jobs: build: runs-on: ${{ matrix.os }} strategy: fail-fast: false matrix: python-version: ["3.9", "3.10", "3.11", "3.12", "3.13"] os: [ubuntu-latest, macos-latest, windows-latest] steps: - uses: actions/checkout@v4 - name: Set up Python ${{ matrix.python-version }} uses: actions/setup-python@v5 with: python-version: ${{ matrix.python-version }} - name: Install UV uses: astral-sh/setup-uv@v5 with: enable-cache: true version: ">=0.6.0" - name: Install dependencies run: uv sync --all-extras --frozen - name: Test shell: bash run: ./scripts/test.sh - name: Report Coverage if: matrix.os == 'ubuntu-latest' && matrix.python-version == '3.11' uses: codecov/codecov-action@v5 isort-6.0.1/art/isort_loves_black.png0000644000000000000000000016772213615410400014615 0ustar00PNG  IHDR; (iCCPICC profile(}=H@_S"vqP,U(BP+`rФ!Iqq\ ~,V\uup'G'E)IExwqeYf:104"2YIJw|#׻8?U" 3Lxxr68GYIVωGL #8]xf̤爣b6f%S# NBcg\e{i",BUl qZuR,i?prmch]?*yI8C@hhq'@[J$bG@dnip?)RP(gM9YzkPW.Rϻ{LRrfbKGD pHYs.#.#x?vtIME #AtEXtCommentCreated with GIMPW IDATxy|Tי=;$ !AA֥.׺>Wֶh[[{_mRw{mJrm"}!{&3sd&@6`Bf,391 """"""""d\IF DDDDDDDD$))JDDDDDDDD+IJ DDDDDDDD$))JDDDDDDDD+IJ DDDDDDDD$))JDDDDDDDD+IJ DDDDDDDD$))JDDDDDDDD+IJ DDDDDDDD$))JDDDDDDDD+IJ DDDDDDDD$))JDDDDDDDD+IJ DDDDDDDD$))JDDDDDDDD+IJ DDDDDDDD$))JDDDDDDDD+IJ DDDDDDDD$))JDDDDDDDD+IJ DDDDDDDD$))JDDDDDDDD+IJ DDDDDDDD$))JDDDDDDDD+IJ DDDDDDDD$))JDDDDDDDD+IJ DDDDDDDD$))JDDDDDDDD+IJ DDDDDDDD$))c@SCmmO}=46B0D"-g~z!%RS!=22`,: AMMuucpq+v33ӣWQDD DDDDHm`X,u`-{(9&O2(-hR~r͛n\w.+OJJ1''x31hDDDD޽`6\~9wL#FD,龚ظ>$z 9? 4)P)~AH2mر>^y!9e8|?:jXx{.Za `:n/IJ DDDDAU,Z_{ S1hO+Wa櫮W8B$JDDDXqش)ZUu#ȹ7ÙgS `lxo?Çk*$W""""GmGr?~ .>1eeeW}drp0v,9\-D#C~=D+w>XD+~]u$tSϨQ`Y QJDDDhرx~gnjXmBEʼns,]z2De9\IMM0sfa[]wa1/^|<_¥?A$=W""""Gѩd?ǣUG_|0zBDD8W""""}-hhxu_)_}e ||;h][ii;a~KkJDDD^y45F?N=b |!|s?t]ZZ?.CDD+Ƣ7~c~ۆ^ֱ6z5""'\uAޝ/kDD䄰Wj#Wc~hn g̙:}{߆@@c!"":^hj\U_9~;ݲ~SV}{g?~FDDDzIHwꗿX_ ==몭4}^HPp%"""7 ;ٳ;߁#:fx)̈+mx1я4GړOw{d*jk~IF?;"""=JDDD^z nMp<wllY˖ۣPp%"""~W]q8fώknҸmW] t+پnIp#nfe7ٱsMϒH7(9tի5b_ eȱzut4(""ݠJDDD3/dpb.YϖH(̲epd7 ۶u5۶E_РKwlt+=(H6Ww۵R_}y&g^c!""JDDD#=qHF?> s'x%_~DDDC6nVH9S$ysO&""r DDDDڲmx!X$oݻ}cܪ5XH\d <ơ?"֯E"ѯUTh|~DDD:JN~'zppkhDDpXU;w_=Xa8;_ S7E Ev MTVհrN&}DDKOX9Gofx/PVoôiiǣ!eSG1./ Jx!7w?ྐྵUnP~%"rD8G`Y ٳaD8ضM$!`! aG"  7P_߀mGXeYqeY|>|>nϏeYn^/. [sK.PUv[Qvc͆m+Fުt+ ]q'9.5rTضmۄa0MMM477@8qh5qNE,n(x:\u2Ztpbna \.~EJJ >ԔRRRx^|>. b.eN/sG3ܔWS֩ 3G r,͙&DODzm=ZS__O]]= 444 TeY`5}: o L@.jk08TRFZj*|^p"}vSUqta:=99&-'W˟B:pV\m#F rmCjlۦ&:MAlj^\VEE/ۧK>'EAU;2mcLrMUD@aY}I_" `0,@tHOO'55~*һMώUiq^ K:Ұy!7Oc }J  Af_e%aZb^Pmb L4>-VuDWcŧx}>-_=')}񭍅]&0z9MsKXQ8C vpXfYm=_\0ro%Ntd4Dx`РA 8t@H_Sp%Ǎ܁~*˧A\:%iV=gYnJyV4\GFcd/߯8E"{R__c;^N8sPO%ge|^^oTJ >Tn7].O4\`qԫ"-`C]]mH(2EH$BsKCxZl@8LO*0UUUTUUE+vJnn.ss 55W{ Q^C-܌,.dw ;B.(Ǐ 76R^/eSp \Npk‚d0>[cj,N0MMMQUu={PUUEssˊV3dy8ѿT+ϜC^r\|>H :6AY*u`f kkkij jnn ,ˊN%ʰhZ lnMqlGv@rss&33͒5r( fgŽU.૞LT<p>HNd￯1IϤ^՞={رc555Il[K(L%@qa CZZdggEFF)))x<:4 =hXOMM khP8X$Z,H$޽{ٳgO.##B dI)FC_x=nGr:.i|V _ 2r:)$9157siDɳuׁWBuuuܱm۷q8=֮RpoJvv6 ";;t~Bl&IM$f{ŚzvdeYUݡ*'AR[[˪UdС -Jff&~M(F}8B5=DԵZŖ-Ou&\!Ʃ@i>-8$E`(/Xcٻw/۶oc]B!n78X5n|J*GfF& "g rZ*6D pjkk,&vͧ~ߞ -[^[]] ߲lc}rrr,2&L Vaa!΀z<ݲ,~?~lF܅Cmm-UUU۷}EBѾW-`bi1cX΢յX&??"c,+9nl6w8P&1/h!h{p+'.#***hnnSb"H)77]].rssox= <>Qnw.Aeֈ$u뫮.h1{a=D"lfƍرݻ-#yTG۶;fMƔ)S;v,999 0[S\.YY@YYm ;vsNjkk#az.]ŋ t#F ;;[w+<ѮkL_N=Np-~ \3W{{񐚚Jcc#HP8d@T @J ݿJb\ e9^6MM԰sN¡0uulٲFvþJn7x7df̘YgŸqˋ7IeYss3vb۶mڹږ[-s m!%5#SZz999 N @U1(?zϘ,~oQŕ_~_ǹw<7~jO`'Tpf L..O8$X?͛7|rɶm<yyy2l0222xSUU֭[Y`?Xp!pT0p8V3thwB"DC)'s`YuN=|3؅duZXK+,,+zh  555444{.TW{.֬]KCCPǃ磱ˤI 1c' 233wl۶͛6knB[l&0zh8pPxRp ڂ+,ދ2ݪMۗ'uj(s\9ϓbUv /Xto \\~HzEB1Ν;Yd {9lNJMMr ՟(PUUݻO}}=^E$v3zhrss:t(999瓖P15`> yNQhM˴pL3޽{ٿ?۶mիWq NʕW^),,$''[Mmf޽_-[PWWA锶c3(g&L8ޘ^q%c1ᛟ=ٰm%:Mm> wTrBYNc QWDŽ8߿+Wj*"H<8h23(--.WD"ˎ;7o/'55SN9aÆKQQ}mSmcm;-SBă-[ī/_N8I&qeqyQ\\Lnn!,MAA̘1{n:6oLuuut\Vؿ?o#;v,}_-Wrܱmomӽu|Q1` }U nT(\G$ $"kٲ.7 غu+-ro琅L؝Ϯ];ټy36l`ǎxFz*7|3ӧOþ1߿ V^Mc~ke?ی8x<Əτ zT^W] -r<.R]n "v1D <_ \Æ逋$O?<`e˗[6Mcوc\C2vXF٥Ul߾7xzŋFcc#iiiSZZBIII4sT۹P:Ӭ ͤ:k%SE8yaKV^M043=]mvm8t'C>0}il޲7R_{2Z.b FVVamlڴ˗e˧DH 1p1c0ydܥU=W]JDW'Lpz5L.tg>ga}{]֭[ru>8Czz:ƍcҤIdddvlٲ9s#~LKA3axFM IDATAAA))p/I{<fdյ%َY=oorvhnnfϞ=_رǃ&%%뮻~1K!Vcc#+V`TvwP2?Y`%9W]JDW'Lpp!|:"a4C_ PYYɼyXf n;~FtŐC6mÇ?lsz>Syx *++,H8I#sȓ9餓ϏOҔn-]~Il@w=ڰts>Z2FKxo>6mڵkYf c \}\s5 >!1neᢅl޼v ;6EŜ Qcٌu5Pj$$^l58,uRo\EPDR˝D$h z)X|/_m;]ƭhueԨQL6C.7}v^yfϞ͆ pANyy9ee 4(C$i +M­xAm2ZAmdŃ7Ӧz1S2̥MS򖀋xcƲzAXP 뉷w{εYzeT|Ăh:[-kIٕ0 Kb+*ك^%6wopl˲bҤIL, `%U\u*DzƇa~xvQFk+> 叡Ǥ.f=Hl4nQ3CQŕ Sqsp5:"+5=T]]믿NŊhUKP98IKK;2ǢEo~ )cNadHrrrcڥ?-jԫӻЅev妕{%|b{@ّ^y_-euu5ׯgժUl޼ǃ㡼ロ>C6\,^fmی1.HPp ^nK6KLZD s50j&kk "3,2LO-z70λV%n½A/N."cx=4WLvhs*ENj02Y!F(r5ICIPv=۾jNL֝Iv\3\\' 9~0գ7.xnAM̟?{|˅8s32e >B!6nٳy'inn&ɘ1cu( !K981]KzoYiSvWn@J+ĖmpޣA!q,VVvV\Iee%^e]Ɲwȑ#III5aŊTWWo޲~qe,GSHqmgoc|)|)2ךH{ORO%3/ni8pΘ)Sؼe ֭c͚5ĉ;v,1UUUN x,].'v8-QW"GnJx?&ݪi *Mg1wMgsl+\$W72 nY eSx_"hI!LR:xWaE0tkڅW6 pk+] LǸkCC{9wxih<~K? j DY=޽9sm۶X1@ y,gq!+*++3gw{!LjJ vOUJ-U'^cLOV봴X6=X%OkMm6to[ЗͲDL-,Ÿq1L Zt)=\)[KŊϳ42Pmi26XthPˈp&k6UTZ!VufbN|bۮd r[7Wx黖xjerI'1}tV^ xb׾5 Үp3e,YܹsJ /;pUWQTTt)J_ȱlnw`UQQGCg13S\>[Ǩ*õ-|9֞#qp{|߳3ߡ:B3׹#9b<IKYN]8::,<+Ϗ#7">DžF|M͛oZclj 77Mgm1OE -RΝKSSˊissꩧr%h+)sc- GLqpb+̔9>Bh > R0=_qp[\x 2MuW3W07TzW`kSRWe|kFяl[c jfa˖-@UXvxES &p%0pCV?0hjj"PV^رڦZ%0-SV}SPGAA!EEE 4+YVXE""HGؼy3!##Çr[aJ6ݻwSQ5W裏OsWsmQZZ.z|3aĉk,ZH㏩ꫯrՅHn')s)w9UGʫSjG)n`V[v8-һ3a|x/ pہOX^c/*nIya}r^iH;Ip]=`C\N4EYǚ;w.o6.JX`CQQW^a8۶mGq=z4'N$''qp`ZimGh6>a%7nFbРAݺiYezz+Í1̝;[o{RZZʔ)S1N4l0]6:hуsS'tRVX?O?UW]waEΜq&y֮]JXvCCS'sW(Pp%F8u.ϭᕃ,7ʞGԵm^ q0{>'YVuPlgpnx2wZ߇} SRJoEYn?ξ[nBKOh/W\N;+1ܹ￟G}x`5~xqp8چSVGAV|82fN;4.0L8p8L(¶m mxxv |UXW\ɓyǨ:'䌲mo-M'Ӄ$|m郦4W˶[!iZ%Zmf&bu&; ڌhfc17 KDZIMM3 ƍcŊ,_G}/|_;老g%wp.ɲe˘kCT >#***1b*\$,ᮔZsLChx6V9=Bxw=?NI{Lk-բbyEK/>29? 'C3NѶNRS}opnp pIR'W+\D",Zgy&!qaI|K_"++eTUUs`67qEr1bӧOg„ lnZvŋ`*>ẅeiyoQRRˆ#(++SNa̘1 2vTU\\=_~7x'֟+tpoʃX_nIh~8,05O;QFbW'`Μ9r-|`WVtmyy/2oj\K8su#@C қt7zy>>нSlj;NA|/oq\B^lHII!##t<wlg1Ca MMMB!v͛ygn`֬YCI_ΐ!Cx'.rv\o¡ʩoWO^yXKꐖƴӧ11,^k'x\q'*55|+z'Nd!-"N!33 /gh<-[;wF+KaA!sMNvwO7;hb˰HO*cغu+^{-~!m_˲:u*u'\dN cTǨ]\C;mkCaSRR1LNy2,fxw'NLjYeee̚5[« 6pr-P^^}HH/ W2تJm ,^k5RׇAMl¤huc}5RCO7>D]s+y]&M|A72] >=>|]b}ӧw[<#w}TWW89r$n;zǴlSJJ \p پ};ӟxgعs'Q{~~>yyyB.u:D4uIh}1' 禛obРA^a:-ZСCٵ{o&]tQa#Ou]C=tucuy!Y?'Mg[ڝM<+]% S t6OjcpGpcӦM,[>?n#///5@~55 zu]ԩS(w鞏d Mz<:E<\{3*˺ELˬ'w2ߢ`wr2n 9 zWQ@:}V8̛7|%1PTT-BAAAfz뭬YP(Ĉ#8q"cv;e:9ÿ뿶Je^{7Y`0@aa!%%%pK8VNoWAea͚5\s5,Yb1 /1c(..x-ĉ9s;wnlx,JWu:r. ,J|}gԑ{6|ޣ\_̙3￟??g[QRRgf5XVkf6=;vK/ s DzbVrؖI*2>,3xp`r"ҧwmncx Zx߇$ .,8)T0 Sj`{?#=9ɳjTooz\5yR%RfZZ 83ffV}p=~GK6LQQl"] 87p+W"GWfks1z{y}G ɰ W>~J.jx4atXxxI b@sge*zBOt^3cE+`U`Vx.}z\dg%ޥwY1n/#X:4@?4"Aj Z=3=~;nƶ:ijj⩧{aqg Z OurmfҤI  ,(Qƈ#Sm4 z8@vNaoc [x:t('L_bU7sss9sfBf^yfΜɶmۢMч@n*bGƏZzz:& fεu]=755q]w1w\wOĢ]Y…  2z-O=yV$v?2ۼYm6XVeef2c V^ͺu~Ƃ x衇8餓Bϒ~ӟr}i愭z*z@HpQt6Q2\[VƤZ2~*T&,^$ IDATQ=7ڃV'A;3j4<7*,c/{ɷ1VNlbq'$X] 'D xg?Ref9aժU\{,_q7n%%X.WM/1swfa|^!C0IȈ?tL5le]q233ihlnfU^u+@3+IZY;y-xB%BdJ(0DO%#;)r'ŵH >h9S0(UaYG3\3#<5"sHg}o 0`@~8&ƶm^}UouVҘ8i1Qt IÇKFK D?֭[ L:Ypʸ`Z0|S;vl%#FPTTDFF]van߾=>SRR„ xg9t͚5}m6u{B*ɠALI n^7rƃ>HjH;wCQPPiFBBB%B,` Gee5gggvZkA,q)0ni!tߣvgӳgV^M~N^ ?!LNN橧d۶mXx17/K2U aV,X;<1gLIiDۺfm"Vݧ{%?؇`җ×I:땭R/Ӌj_!FJV kV,˛()ba±NO@(X|9/P _ ##g&L 333✲2Ǝɓ)))YӦkM0|QȟS#E_ U-вeKFEbb5tP>StޝlU!$8Bu5[JFWBe~ÇW"S+?ҬY3+_3Bu4-jUŠ(++ \0r"sXVjOႼP<*"l>cPU\: N*bHV^(Sl ^<^U! ^F߁t`RJ!Bs.$&&?ΦMxgINJLLdܸq<#믁ʊۼdddpԺ`E\Y`Nاup>3 fİ1ݛe觾zhT@"ʹ8D=4}6ie1d3τsXXp3k$~wy|^(27~\%Ҫ3i$iӦ ͛7?RF22fqrss=/TJsNn6 ܹ3III " hRrWc+~*q'@ `Ȑ!yUnRX^{ If*KÔEV7^R"v1'QR?TT՜yL!Ɋ$M̨bW"`&L);a6Gat k j Bt=}6k[~0x#Tbb"GfĈlzmK,",X8.1c2hoj[8SY$bx}Hnn-Ҙ-6ZQf3:w.Zt!)'\fR`؅CVV,X8Ѧ`(--eĉ߿3C\qJɮ]p=akRV,ʂOlh/U]:s5aO*|K=yא?~־ZVV7pI,Y~vmۡizK5pTY5+V`ۑaYLqqq9 @>)[K232Ð&BлwoZԐy[VVƬY@n)k\wuzuy<%?cI#td_]V(.B?@w s1GCFF0ذq#ӦMA1¼>}pM71cƌ0^SN4lzG`BLi̵Trc}/iZӼ}X֝o7~xq {9WGd >l(GotwF7T<NQ%z[`[`cRJ>Cl81C w>b7n' #[D*0 *..'cۢV!+ uThٲex^M6#Gu5Ƴ^zh7xlU8`5J;.\HZjHjLO>׼iӦcE '3*I7d9O&*U(E*)`=ƪs|2̣ˌQ4{؇+ٰ*)^tE?|xUII ?8֮aÆ$&$W+җsFf&aif&L@NNrI_W{֭[kfݻ_ÇG%{OvhV,X ۤo=.E^N{|J+C5.z;/Vɔx8`g/q[ ~9zqR=e JNddej±4زeFJ!dx ”9(M5j'33ƹH%TB)/#{0_WJ!gDJ0s~ 33$y=q Ha&#z~?0ȨEO>СC8vZ 7P-˗d2q:f D㢤0B7mѣݻw瞣 c)U YMܥ!q 2ZdϞ=3ꩰxה00 פ(Pic*^32,P1xa73 9! 2 _Z`<RfVQ|#zܰN{Vbܹ||>3O*4^I?ߤ  #3JKK3f ~mxq̾g}ƚ5k`A"iny\jKk wLwq+Q(;1k4KWo$BRtlc; ǛošCS\vet5؂֯_qƁrh!} !KJɵ]gnn7dee~a&`T$ |>wQ3w\H)iۮ-ߪ5c7<f̘IKO #H#I<)%s뭷VK&[oł HMMtV"ZB5L*06lXYg,[,̸ʰxP 1dE#p݊OX?ȪJ**@j'KO Ej(*h0=,Zp@סO+,ǿFO|g>s37! zL2K"E˖؄m Z1B_a6~b{ß Ү];ufs㏤aH+}E\','wa?_zUJɂ ذa(HJJbUè/͛cYz5>(!]MӸKرI>~\#˖->,ʂ#݊Ec_2D{]?YA H|8bDǰpBʹpcG+,w%I!R,ZiӦzr3; 뗎EbFLdvOib˖-! nUjtQR*=zy7\3i޼yic޽tarư/T!x衇9s%~.C&M鶰0)} 2lذjJKKy'پ};h:*%q!+f K꤬ y)CQ"]WY`Uv~Qc(LUʂ5izQ5kVN).]ʛotUf*2mvM60 >cCBBÆ 3kPc}D3-XpX8z_D'}qtt|3U{ĉrR/Ie+ ,@VV ,X8QxW d`[IaaiH uWzp76k˗/G G'pi=5Yr%iiih_yW+_+m۶1k,.+2FUq<ӜuYQ}[d 7|3yyydggTDF_4M6i\J># HLLx\( k&&k%$XY[N'!{.̛g‚cqkײn:3I^{-g̙3߰$''Iʟ@]*@V{Rm۶BideeizLr(MK.aĈՒcĉY xI%dM駟iР;w_$3ruﴴ4FŅ^HϞ=$?Ά R(ĤPfZ-@z T{~44"jNϷשq1^jsmY s;vl~2ql޼ّ$$$r(,,d@\~,\!;]wO?qik' GƸ IDATv|&jNH8sD z3(Rokd2( dD9~:[hettY-O9AQR@4d~[Ƀ -X`Å.BRIJvZ{= 0I)GVBJih駟ٳcڤk3#GtVy_'%%ƍ3lʂ Ɯ9s8p;v䩧JZ\}V~~U ܹsygX|9$$$ͦ !#I.]=.sTTTDnn#G鏒G;l.~iZ+/XE>@u0 KOOgǎ,^e˖qgNQ\vas2`ZiOdX``,ɩZg9նFo8;@?<ˡV/F4p/7lU~v_7x;/+yzI%-\D Չ.W*\s휯`f-d 'ڶ()bah/P(4MgϞ&Y~O]vaو3%Dait֍**UMAl6СC%R,X)SHIIaqճ۞=|Scuh8p1SLa͚5bu6lH||P+G;AUd.-"!!yijz'PLUGpl<2N?Ze*0fh`t:={'55ꫯR~}u4Xĕ I ^&i桻v&!hNprioד^ |VEGmk7]]ލJr饜o>F`ј'şn#ݦ]E<-^K.hdAN_}e‚?}q۷cG! 9~{=HKKLvŊ+BбcGn&s\dffO0`*=Xjw}7dgeѿOyyyl޼D|Yf1~xlق脕I5|!-[d#LWTB)~&M%+++Зh-*UQ=irj}MʚS~ DY ST- ,|JP""S)%Cѽ{ 7o}I ,X1XvؑѣGW=QYY&L ??&" XrbPv 񔗗3w\s@&MB}WrT%*+ Nu L~hm YvVyFq::ٹ\AioS$0ϗql4s&<KDctYWN|i:uV,,XСn}BWW'DuC||hC]\\̂ |$%'SZ귤L:nv3h |>nMӰlPJQPPO>Ɍ38pq񤦥ҶM[.Zɷ*bƍ]O W3}t),,R^/=⦛nyĸqѣ׿\5>Q _ W^ye}ںu+O<%%%dffCI0v5udP󠎌P2~xSr[駟矣i!2H[rqA-[ƶmhxu3:%KkxjMȝ+ sm)t[٣~W:h܆īhPkeԪvK_8bJ\K<1PI|iS7(%t"Ƕ1%Y֟F*+ '2`H+,Q:Z^y֬YC||<5KUKEN%C?+Uk2?jFU{R[U5+))'Ҿ}Znرc)))!--M!hD+v A9ݻٵkI\iF֭|(@"OH _ġo+fب_:{U|i@G9Fk6ȷ$8Wqnd/;r:k+E_7ն=>c;dI3?>4*G YbWP3a;y{$"8Ĵ`pV ,X#ѯ эbonkVٽ{7EEEhfff9VJwqs 7p)`uWR S0 ày1g-[Faa!^AFquY1y}kJJ 6]mxPPP{"",Xg`V¹؎`>!$)>V(c||`TE_׬R%B̶w ussji|m"H q9D A?[!8žxvJCwR;\fwX4&%hFc yݛ&[b-XСttBtQ~#!!4sc-dӦMaP*`]Oϡ5}N3sL|Mhٲ%iiihтF!`Ϟ=l۶~mFQQ23i蚟R?:zj֭[ᨳnG~i^quGw?_+"{1CRR 'TLF@tB43.R*F\TǦ ?ZT&SwQibDΰaøkne˖1uT ]OF3["aATv~r",Xg4;c#Pro`^d I`-mї]) $mwss'ݝ.\vɸ ('UGD=f/뽽H9极mwβ-%]8SF}= tEg[^+g2ል ([{XXpqm5x D"͚5UX3<1nczmvwzѴPYVRJu _?[N I'|ILL@*YkEyxtv8쳙{TѣիWהR2k,[t]f*ݎnѨaCwNvURSٳg֭c_ǍPl׋7 RĔ iV,X?c3#0fc{ F[X*"~ D$iI6~̾Уiξt(2N@ `k«SVޘ:‘;ܐPE#$9 !@N" Y1KFDyL-6mUW^Ug,9dnf+ED VqϋSsnK.o7a^Z<}TA0.gϞ7|sk4x?ŀ?I4b|ML+ID\ BW*qGRJʢ!8Xa",XPoC89(=ڧpe xӨ#T z1IE|.Oyh xݞmkim>HR߸!=Zxݞ_͒Z8Ѻ5\y% Z:aiaʶc{QU>*6tsHEPpZ(wAƍcꚔo͛7p8*HEzT^?"PyFZnMff) n{H8ټy3NmTc:uȑ#۷/#j?p8СǪW={rVIH)Yx1m #!p:q7{7^WgMm3$>]a ) :v!Cp]wJ??FJin 7Wg1`ɠ $P5kƸqHiLJJ #F mͼkJBkr:{̝9|}rE5zȝ8~vb5qvN=M41I¢v/i& ^Shc7R47׭XG3%+ ꝴCdvOgczqcz,x ~ԛSeܛ>:l8FЦ ڴZxWJ~PMh޼9.+KVYF;NVdz*u]Gݫ$ ?dݺurvɰ Ѻuk^{5~m:wRe&Zyy9Ǐ /d^OKKo4 JMM^[n!x<̞=n>-\3gdOMӸd@^{5rrr%m6sp?@V,\k.ve' K*hB=V9?=fI+|_W^,s]lЎaKC)/&&C#Z1 H;Mx} H1.&`! `+,7߿N мys֭[;"$k999dffeiꓕ$r3͆M1Dt Çkep*XD>1)Ǽ.**bɔrETsB7o? /dԨQf*E_Ve_yȨ{w;u֕4nݺLaaa׊O`ܸq4y뭷߿p3}ETଳfҤIf iԵkר&%%xK#g$ ^Zq-(((ШQ#N + #ž@dFyo~;l$p\]L#[ P'zm w h`^iiV,XOpBФIU _~ 5kFfPJa,3zJ"raR $FӦMy'~'xM9ɔ$%*LUuKΝcs?b TRE1x6GZ-Dž,a=xHII1 tRN7lbe͜9s+j壵i& &Mݻ̝ϟalػwoZlY-6uT6oތnCE٨"--I&HZ}fΜIbb"]vYSF1 5=?躎cƌӢEja3f~@4fW yHKKC)w}5\cV@ǃ:J47CcCF"ʕ+MJ)ENNNS`B0eFvctiIǧe|XT~_ZR±gx^,32^Z>QPtFKoz  2u=tbW74lÇ[q`>1|h,MsIzYjUXE2π#0ɖJ#^V% ;'1)ŋsӨQ#hԨcĈ$ nȞ BF#)sq_[}x饗(++G_)v{@R&M$+HZ'q8t֍W^yL﷕_'dΝ&MjGg\s gϦ]v5f)X~=7|3 ,p8"HGk*Xj}akzT+DΘ1k-8k,3kyo߾l6nVv;a0{l>C.?K/vlI&L4$֮]СC)((_~axK%9&e8ꯎAZ*Lѹs+sZĕ btTlv̑W'_/a1üw+^(Buj]P'|t{#ex} d`bq ?Y t`W@B  j'KhժUrPM6믿9Czz_V pPTM[o3j(4huSt:;8LJ)YٯJhX%l]ѣG؞ > #PBawТE n6z)B^amOr]6=z IDATxp$D4nӤILB-Bχ~A.D#4{=,X4]/G]wU y[laȐ!|wUX,3+B~~)L~gG}Dkefq:KV!^ٱcGui^z)#GIG}Ĉ#{m۶҂nb"O?4ݺu{wիW϶mۢ^o׮]L6 ʬ xU{0 \\tE;vi&t*hW,Y(`t1l8f+l0۰^{ryjq=qE2-[Z<]ޑqel:Ē.3o;KU_a,!h~؊ @eM4!33Ӕ q`ΝСCj*iRҪU+z-=馛&&Wd5PIU rJRRRL1cҤIx<tMC Nҋ,];3ٳgSt8uFdggךh ǤIҥ Bo?W\QmLׯ_ĉ)++CECK%%II<=iyZ oQJDcϩZ+oٳgadsa̙Q;7wf˖-U~?;wX~:&L 99)%sfݻl+1s1:5_dWYhJAYY=mbǎu]\2@F?V# RJڶmkqFvi7n\+VΙ @^͗.dٙ4-GaTlyEzQ_ y%vgK.r,$IbقO%oCXY=ul~0.gsIňe} ,\V+f_?vY`H!'ǿN.ТE RϹꪫLU||<7x#K,Ƽ9MIIavi6"o۶-999l޼vx4h߾=^_|l.cܸqrAFŋ|3Ac6um۶"`ǎ 2͋/H^^^ߢF?7믿rz)k 0IIġCxطoUiyL6l$?>ӛJ)Ŷm3qDy*5&M~6(v+bz_}W 6$ R\q?CO 8p =M6Ea̜9g}mJS,Y A fӦM,\$[nd$?>eeeBM4",X#]heg8EۊL^ Jd7ܝRiXy'6\?sG\+aVk6,Q0&dDYWz{Zqs~$A@UhMӃw=A9Xp 7zˊ G ?_['&fK.᫯O^^嚦ѯ_?Zn͚5k8DSmmv;<~lؼyu݃%oā87p U)ŧ~ݝwɨQQF;R<oe$''sWXm.9`~9mF׮]۷oꫯ9sдj <\y啵h?N"XTX|⪫";;F飏>bf6R~RW^k4lذjÆ L0So3gsNNϞ=Xp!O^uo߾2M*_#k6x\(b5Z4)%͛7Tys۶m|駸n`5J"-ʂ M̗.DY?S4wJa-3Ǟ|h$1i`M!Xh$cəc;+kbQ|Q&;<-Y ;EHbiuf};TیMѢN JU+==iBzp"+a4Xڊ SN9a¡igqlݺ{|tܰ6mڔ[oÇI ́oE0':dhۦ-W]uUHEbb"R ULaϹ!_%.ɋg5t:?aVGyiӦxMJAY/B8pI6mbС3eʔj{nz)LCI.x e5X&aEkѢE6l؀0i$l,]9s搒Cdq^V^jqE 8ݻwSN:w={6 <#|qpL0 fX,̟?;4YX4{Xj.y x`qǐ2,]FvɼDGGۗ[trlo6{FQ}8]fsܹtLF Ɛ!C0 \zGҶmǵw^>3,);+IԫWI&o{fO?ׯ;V@pp0-#IQQQX!2k~7к/СC1 9rsI4Mz92_/:ԩSٷo7FUU\>}:[%z5nܘɓ'3d 5,fئMңG'Q4998\riӦXV%=EEM朦pVS8)Dj L7BCala8z_iN}777ƌc\4yUYJJ ֭Ȋ$IԩSXVG&66G _ɓvZFqQVBe4'O2`QU2eSO+~EGGaÆ\RN zbҤIq%NŊ cy<DPP3g71{:M"^̘1#IGe a,X `AGOOOFᅬgΜaСa*FSZ|ݵk˖-cΝ|̝;/ǏgcCe{1*UT|H'm۶m۶E^;C``ܵkwFN /Pd1ߎ@  K}ysa (4o/҃QQtBڵ9{<͝;g:m4h;#?]J\Rp*|tؑٳg;{2sZy7Pb;uC寿IPvmׯxZtoߞ]C 6^PQhԨuM?8zh ̝;www;F>}+PdJJ?qd֬Y< /III̙3{{y1uT2d-Z(Pɪw{[e3'OÃs9reG6mԩSˬYsTTUUS f͚yڧlٲԭ[7_eU\h~-cƌ`0vfrsc^ʔ)S %I\rիJ AQ>~<-[`0SOb6ood]ҩS't=:l6PY$&&rq+&L@޽yGxٱcGnOb+?^H~L&Zn]dɒDhh(gӳ?]F#;w7$f_gan8HϞ=ҥKDDD3ʘƢEHHHW1b={,/sNJx̙3!C( _}=z@ŋIJJs\bĉF.\ٹs'6 I(Uov*_~s˾F'|5k潎őj$Uƚ5kӧfUVaX(,˴jՊÇ;Q65kq#(tޝ;@; @ ƍa a0̘af`Ek׮4jmaXꫯضm率3f̠YfN qy'-UUYz5͛7o߾L>sifkϘBy8'.U4o~Eyy ݻaZ Ee^jϽ s_/SNZjl,_e˖9RN|۹qǎvza2ի , 00 ONxx8AAAԨQqFDDp< :t`ܸqL7.. 4 >C^yz=;wdС?5k\4ۗg9իWyl0ׯ5sαpBsV /O/w^R^v%5jj*{1TUeҥ_>GmeP̙O>c,f.d$_Ö@ E@,-];TR7?3g8}6$$>J*9ZرR&2-[$00TGTamy]P>}:=XԩSiYxzz$IܼyׯS;7}3 s۷og޽5… ӧzK.1qDbcc$P9f3WvmjI2|G"XF$Ze=WZ,ZSNZߒ,ѴiS6mq\+B:uXv-M4d֬Y.yVY0n8P_oQ|e"B@ (*vOlߠ lۯQݱioӦ =piƉ':ufX$5jĂ (]Lja՜?Zj1b 12HqsscȑٳP!sNzͮ]s6i$4.)d݂6mZ mw^^\.v1rU4 `۸aZ裏3g!uUm"qNm۶,X4M#)))RIII|'#IKO>K.t:8q#ϗ^'$$@ɓ޽;zNHCUƆ ݻ7zxƏt& &Pl|Yn$ 2$0St eڵiw7ƍyɜ>'pbaƌNdYSOѽ{wQI0U@ C:0@׈iC>zhWڬV[.\y>C!g_K,qlEa <8|M!9%5jǏ/TV+VХK"""\ ,aX||| r-h2i$a6p@Ξ=FU TUɓN( *U?O>Fh5i$ )2 Ν;ǹsrOO駟Rti<ƍm>|2egѱcGE!55)Sϱvl6&4(犇R^J`i&lܸ'|EQy&ÇgNyt:ݺum۶*))>kJhذ!?xm$&&xb3 k׎M7Q~}^qDFF涋oWjY0@UU+VX93[8vx|||č2p%@P\Fv3zP׬Y3f8ri@rR23g%t՞/)(X,f-[7|8͑GyUpMN( eˆd&LP(OK.ꫯ2tPbccB4֭[ĠiJ" gEL2,^#FZSU^z'O.SOl0LkF4i?>(XV>C&MTQTn,PJHHd2֭k֬L2hO^(SLb>|LÆ ټy3ڵCeҘ8q"S~(͖]lrpɲ7Ç~pTk_/}[rʌ=:_4UUټy3?S.1T\C WJXUP$x7Ynʕs/:*`qeg;m O/OON~UMعs'^{RNJ 0j<@ka(!Ƚŕ$ڵkǛox{SرcrK.|G:6R6@ƍǎ;{xx0e>S*T([)d2vC׮]ٱc=z()##KҾ}{GuDEjAAA<FǗd˛nݺoѽ{+eX͛G>}\z2ebfbbbcرlٲZjΌ3:u*)))}111ۇ~Z& IDATNCdǿ9s&| l6-Z/L\\\"bVedze4h$I$''[oިtɔ]]`c̜֭9TUGlݺa zcƌ)0A~TTs̱{JIJ*4k,6Yd  Wκu2e ^^^l6/^LpBk||5sKo?ܸqў`{ի!*ɓ' 3ϜO #`LۚE^5o WVtiXʕ(@ \x1s+#G裏,Ԯ]roZHHH`ΝTP5k"Iݻ( gΜASLDB$EAc0},t9;|/ʶmx7X`ot2M%--{___ׯOTTTZ=z`_8RqE … s'r> .]) HĎ;dŊ!ݼycDz`'OFjj*?x ڳ`EFf駟Ҿ}{F#IIIL0YfD@@/"!!!yWvm7ocǏgٲeDӰa|,Ocǎ1&6mڰh"FMʕedfϞرcs }o߾@>… Y~Z,QV-^y|8y`РA,[0E֭[L<ӧ= ,`ۛ & =<Æ sxxHLX,\AF ;0|' ; #_gv<}؈˲LFXt#Atv`Ν׏K.)t:~a^{5zZiN}Çٸq#[nСCSY`A+eC\\k֬aDDD`(VWQwμya۶mX"Ee~aFEN ]IZ|MIi֬)~w+{\#Ft1 `-J?gs'EQU˖-I&DÃ^{ބ2B*BJ$9ҞG ӧ̛^^DUU[TOd6m'|Bݺusmcbb6l6m"---OD$G(Tpp0ZRJTT@eZZqet{%11 EAӴ"&*`Lǎy衇(S B牌d׮]DGG(J!DlcgX,c2h׮M4vڎpӧO?ߓVȬ>xiٲ%ժULJ[nqm͛1!Iٓ{ wwwn޼IDD۷oHTqf0ڴiCӦMVʕ MӸ~:gΜa׮]l߾{:,h><==9s&͛7WL_h˺>24>>̝;}駟Xt)[nMX+MgQJ\\x!CΝ+R&1 B*!\ AAW%čЯl&l!BU GUU LlM'nݺ̟?-[ܧl2&L@RRR>B}]UUGxY 2$9BboR3Ǚ>Y [u38%>t:>Ӈ:E$]7Yf#$$///TU%22ұؽ'Xk4ݻ7-ZvHDdd$_%"""[7Çr{jFDDFbΝNm{zz+XSB*!\ AAW%Э;&l! C%f믿fРAܺuM bt-j%<<$ӭxG-qpQ,nΧ$!ȼgP&'( LUh6]zkLQX`;v%>i/94Ѭ;fbB*&0@ ]reXl$#)_޾hU(B.]Xlrw6mNt:ZlΝ;ݻ7nnn.îV-H%޽V&Caݡh%ݝ+V1KwLbHKK#55KOle֭ٽ{7]v%>Y,,YB^x*Yw{xAhuJ n W߁?Ze_ۂߜ2:ubŊ+W)4.11w}aÆqe獶$QlY,Yʕ+)W͡s iNkJ@=c*,hPQ7o| ժU[n1fFAl\(̒OV%qo&@ 4ib<<-l<iF\\,Ə_~}p)СC:tW\qh4ӧ6m^z&VST,QUP  ~7/嗅->w:222XnozͲ(2x饗0WU/F750.o=%Q$ F߸[sX&֊}k{$F#<s!,, Nڰa'M3l69Hxxx0aD R< `p%!\T?OBgrD}G4:ĠA-ADR,R!\$L&*T`8p{Υh_ڵk˱Z*Kz饗ؾ};Z|u&xrJ:?S_1\e!۷,hbqth9dI=0j8Ĕ>x(e}} ڹOIbp|E8! E.CDvߕ+kTV;2e 7nrÚTU%u&NHǎo4ӓN:ʕ+^:& (yzΥ5xJۄŜsrL&e˖?&""޽{痻Mc 5gϢfE!((+VpBBBBčn6 <ܼLtCesJ}KOaP*.u$d|[f4(ś Y#AJԯI<"[7XZBbj^O۶mٳgÆh4:i+޳Ν;/r\ek׮8p/5j`0;{)Bb)"*&բF#<ڝ$pF}Y1 /_%KpR8y$M6OX,4MC|77 kW^L&qCLMI.]`:a þt!*UٳgO?QfMʃ}ax Fӧ]?ٸq#?8&B!Z?]hEVgjtW:O_Iwڻkfkw6'dYd2QvmVZEDD}St&ME,_UUzʄ~zVXA  Lm"K pWhFz8 5QQ1ȴC:A c0s# 6ȚM ]+yAM*t?nFU1cJG΋ƝKL T⁙x46M[)ϰKs.m`ro ۤaɱ:=tz)W⍭vpE{&dGB_x lXWf-@ڏUW%^a1`0P,~UաꇠILF2o0},?C߈GXa=DAhfшA`ߑLٴVXd)x>գI/ogwZEU"HJJ214eHKH%,eӐίa¯$2dRQ Vl{fA1*~(S7r*͵j'Lk {|n'&z^)$˅jטg LÚ"_;H)H<Ӡcա4 tG} .NBp5kuka8{ڵklz;$!29~Qr<۳l\xիW3oC62V{Yc@6Hfg#Z` i֘Y} ]PH6% ыcub3͑?g<š?V4MYq'kIdFEqT$9D+d[5+xa蒢x}$N#eв!sgqeVm=ˁS7\ jU;*]Ӯi} gC$Q[W2x"I-{B2ˢ ?tU0S9u0G}n^<579(IP;eV/>Ōla!xdK$YrRI (Z^uaݧti{x`f$IZj,]3ydC9ÞGӰl$''1sL-[yVݮ0ۤJ*L8!Co>͛Ǯ]e sF^ybd6 -tٓ*! 3l^Yl_KY^z=-[RL5˗/_xb*fӚFj׮ʹihݺcxZ6 IDATw3 LBh/_[-$bc\F-ne:cBjkVڼ9\>30#YU%!hDQSTGD:p]Si275@Mc!맬HtkŨ(TWßaˮ=ٚ*m치U9pK*QP"y,ċYkd lqwq}qgUΦ1QWi6 Q*i6eÉ+OSvQLň5YQ|Sr"yCefqlR>ښ(THZT@ln#:3^~eh6иjֈ\Ͱ1Hy ӖN'3}-,4QLla LzjCKOk8ˣR:t]yҬ|5!+ךuzZhU+V4X,\v{5j0j(>gAAAs{4C.a~՟#Z41̀As^Եv_LUX{-Fz:LǰhYJJnXXAyx_#GRs4{`Mv'%bQ%vʖk}ݸT3>$Q֨PCGmw&ɤI^Tb".94g/r4QT~"oEr)캘@Ӻa$c|i_nk_;ݺu?pT `4>0?@ZZ6 jbʔ)DFF}v^z%L&SKgI* rF r]ߤ}D*ƴ"IW:^Cl޼(ϟOqsssybaǎ 2кu:u*iii5o-[KsQ (,LzmW"%.L[= -hEuqʰNsyO<r 쿚AFYy<[6 ?-{A-;7؃ Yx6Mj}2E-jkЪŦ2P2V5MF|:}Y40[mU1ЍQmҰ&$lUnMQ2ߥOp Xs*dUbY/*%xRTUKySh^a .sF^z) | FLҼS.YYeÑLGٗ|DMC &>y|{=Ĕ8ƪqo'@*V>#aFaGV???tB6mؼy3'NŋꨤfɬlΞ={;v,knaƍ($IwKY+q0O͡zY+l_S%6`NwfZl믿N&M(]tbi=z7tR^uu3ydvJ``9Jw\.YYo'm 16,lDFr/MR\$VD$J27ìCWѪ }Z6jI,ÆUӁMdV󢼻F\Re+ hnS1$R;gMi/$ICo 8GE+Md-\fաh >ZkF[XpTbm}}5hU 8 9܍2x{|;pJGLFz9qek? n:܍$sqSj*s4HdS:>}~h0%1h%vda@F-54oF0h]==sbb&qbZl$os^fEzi,=F . ]+*zs=ǟɸq?el6̝;9sиqcO?MժU|w ]vmۖXΜ9_ͧ~JbR"NXGĔ".[OMŭ\AcA,EQMU1Ջ>}PV- l_~aժU(jh[aZjUfϞM-7"J BP#-tnj ,xxrstY-H(tsl^%Mdpbcǀ;x[E6#PVH~MlB~Tvի͋u W ֧}Ew[يh$r%g;\ lcRu뮓`{.ӶTݛW̯I=)6:rjWqU*H"-LE'9>XFޘ}ؤܮ:U FޤixNB]I١~Jt2$H99<\%Yq&MB+x Bh6G+&>14oP\wXByA9Qz 6 wx}=ZBPJ~Ko.*'= oń29Ru5tqB^xPCi+GJQ 85r(~34kiUY|֒ =˕>;(WD}{LMmk4BrhtWԵG:SUQo)~@uo^\9TXO-w"K\GCSyzoOX >yxom^y0t1ztRJ QivUYO.ҏ jnK^oMW;L];uPFLF,6}mj._WM#!I/=NS~(f%Yh@=<KTXe*1ɩ{雙x8. rGYtPSOajw&}^a֩BC3ߋqah *R[Ouϰ:OTFokϓ4]T}`!9ѡK]H?N=tO?-wP +!!AW^y{Lo3T4epU_CkIf͚'ꪫR. tICСC_ӢEh"tp( ~9Y'/|zr:w<,R0ĉ5uب*i׮Z~VXW_}UǏT8,ŦJv,i_=C1c/Ap ~D 9a Ѵ%CUVq4fE&DžQ~Z}зvg \gI%(@",Wc5-omZ@C %_{ ޓ穦2;GHaIQ`Z7;cwӼtϨ,#CQ+cG㭚goK/h.{p$Hhv}%5|˲ Gg5+Z,Kyz/WdB ߲Qqܚ|}FV/Z*?Q\?͞r$:UqX/.ک5'GřSI`&V*&=61SߛtflJTUSkWUjИA}[][~gJBuϩl'umY4Kpv/HGtnPPSpZIOԔLE%[ND?.Tgsؒ" B*fs:RVc7џ~$U%T=vh $]VtB[G͞QR5V C%5zz| dx=)b86ڼ{~⨊hcoPȯoۢMy2 v* լY7w4u 4MW>fϞ-[גKrD B,+^z)bM0AJKKkp[#+''G<󌊋?X ,ݻt:cpy6+2~eZYXˤig M7w 9R(V߾}5m4]{P\>%%%ڼy>C͝;WUUU'FcCl!өP(1רQ_FVs:SG6ٴtozekDiK!Ynm&S~E%R#+29CK7"Lk  6YNXN=Ͱ*m}ݿT}PVJK4ϲ m/ewO҉Jm*0`פGCIVDMh|pԝ=a$"X_ Cݦ -WD`_XOM7ѩ:++RUkRyQa(3ţΈ|a Z Z4+ѡ˺'WCG|ZHO~3AP)U+ah@GWzTkaXj7G CmPsИj*>Չvd(2zKra]tRJB:χAɦVDbS;{'ؽ%?nr{&:5wu6BURJ{ɮ.KWF뜓]ܦ8B 3a(]jHVYuj5ZDT^P~u4aSzzD"* eEUUJN͓&Mvh rJ?S%˥p(>t rݺu 7hԨQKp4/d0TIIuV^ZϷFc"[&dFucFlڟi$M2EƍӨQzz޷eڰa>#-^Xr 7t?vMO<񄮻:edd4y$pֿ%0@?OQi/&}ϸn|Bm1/u҂hZx+(?S\2Iw-R |)=ZEUWW?׼y4o}ΫG*//O/֜9stqy0USS{C QNNwÇo~JNNVnԡCvWQQ\޽[k֬իgC.S`v\cr}iʔ)̔凮!joŝ>"-;v.Ԥ;*1m091ΐihJם*Z !jwOSL.=\`ڻw,Yk߾}r\b.A!40MBc&OQF)++KӧO-D"TMMJJJtQرC+V^<4e|GQ2M\.gde) /{V޽vu+++Kԩz衤$%''Hmᰊ;wjÆ z7$IN36ta ѣM)ShРAgd#j+@{ApUVJ3Ԣ=yQGJ PaavLo,X ˲bӾ|XAGӧkĈKt%''~a|>U\"釒Z۷O7nԺu짤XP Oio Cn[nw- J Ms8߿t"UDzN~H_|mۦsƎi2MSH4*'MiӦ+P߾}p ^\҃RGrӻͲG7n[o+WJ<BQKM{KHH3hTNN>}W^ڵkV;e¬ Î VIDAT ~tNNgl׿VR Pyy>㏕;wJ(-K4t:cA9RvƎ~~& WmD4*-Yb7m?9bmLr+ɒI;>HDeee*,,۵d-{YR,t !<O$1!Qߚ-eddhҥ."edd(%%唑O>Ov޽{' qm5fv4M~I_[nE#FP>}ԭ[s2 mU\ 6fZi4jі!/رmeY*--Uqqvڥ?PϏ5 8j5vZ4T0#GjܸqٳRSSկ_?%&&sαN_؍y j۔maUUUD>O~_ӡCqFZsnpn |0;4qD]veٳ^y) UҬYҦMԢ-Ζ^zIPyy${am՜NgzJLLTjjzr)%%E;wRzzz,JHH]2+XSH$ UWW۷O媪Rqq!Cip4!2d:r8uV[5f3FiivX & WmԡCzM,wRZ@USSR(??_k׮Ֆ-[~h#P0lp%ˑL_(٣ڳjҤI LEQ^Z>ﴏu8$xdP GIY,Igrt8reɒѣ5|pzڵ:8!& Wm'=4gh~:wD"|>;vLڿrssjup8d:vsrRsWZ3ZjJ\툰Z-qnh+0$CF뎺+5a  T9<9 1Z'_ nc Sh)AЗ|F_ؙT8blpC95  "1c<6Ʈ廱JNg6|/2KսW5[=d~YZ04rIOag Zְ&p4_!P_'$O1 ᗸ\Xp&MTrε #{/ Gdr,K)w;Y+x rr#}EE'=`ip < gl ?;ebє4/3+I !N 57i~I҂!*_ | ulY6`E$m^8ZosJmG ]$8 -`̣9r¥ n&*g3A#Vs/>ׂ/}N\_Rifٮ1JA:;tzE.vRAԤ/.&pm:,f95J^FR*Ѭ3GPsqMks)mI^apKՌ2s1?MIik45%/F향8|ʍ\+3bLoLYTa D#'kϚm<@.2bU89ZyDJCžy#@ ci'kMXbd#4Wfje-m=5s)bN3];(PҠ[Ԑ0neڎzĆ 9{fLԵ4TcbR {s,9 Q  %a(e)Ī+; UfIp dQ%Wn^꿟aA'dTj#5oW7VߺCh"I5ھ%W.[DWj0uʱ)]NXu"!uv8E<QB5'Qi%N9Uo{>$*4gz>#NAr ͕j]ڬ@=UӔޒ+`~+Vi*V)D սFp4[,yę&h\@@;ru93Q /|3#(:`}:J'ʅɫqt4+L#)a s G/*v4-.WcK\67ym\7&U? yv +j-S>נ+R%*nwUI;^:+1-zyQ ?$arn!Pw, }.cWQhC|mj-Ϫ׿0~Tk &k( "~k\ҏͬhEX8v(#*)6KXwl`Z[L7QP14O~֗?0M=? mZs45I8|!l+ՎR"]<6~\(H2',<^2V9E/aκ*IN]"l֟'ցj3q@(Ly:ؓRwM,g޿Jbz-'26etK_wǡaPJHŌe=lT3ZQ^Qٞ.{o'4Jg*Q&n ()d/Y pa3+LO0I̍@ٚ&Rx.xz(CPt;ݗ˥#v.7ML8ci'OWzXD$]%yW˹Dy8$'Ϲ:w6॔5ZhmYsa/I.~袋l{$0KKb{uKt }0N3Y KɶN`0D)}[& S"mDbEPz3+Y_y,`W;{'(Sj&gNW1 u [³28eq0I9{t^DH[໯^b,E@a{&]y A;Ye+A*.| d{kGAX=Ѿc33<O(z2-a98bcSޫ539\!Fi˥նqw*xÚzg1,,>F-]xCfMqQ'--dip9G5CInaXEgZ'N%pv9+9(ŦZbHqQ&(u2tb$QUN6[c<FkI@( LTm4́(ݱo O,`;=m %&΢`.K=pBu_ cs!<~ N?0j]Ώ1$jk;s`RPIݏ ޝ17rItG'uO*A2^A,XsܝaRay 4 #n䪤orkmK ipodRS uLT31EQJqxp=v=͊#TX.48d-dU4xS A2KǃhqsdnJ9Lrxp0/Ep‡<);~$hjXY@ORz7c|9rs}%|&2 [`987 |6vs&}U[̍fnUe30lN hmGɬڥiB~J|A`wl)+ui]Vs7tc .vFXto| d2CɬA`GlߏM.͑pXsOPڳ/2k|!jvpi\Lǯ˩<)I|2YN I3ef Wb8 4 9{큓hεM\g j!S6k*x QHX528J!)/6*NJ6Xc6 \fJLzadDR)A;#`5={;lzcE,UJE'CNtT:1  АR!# |n>]ӲNBw}/d$AurjrA9 )AN9rtЬK])IENDB`isort-6.0.1/art/logo.xcf0000644000000000000000000002256013615410400012033 0ustar00gimp xcf v011BBG gimp-commentCreated with GIMPgimp-image-grid(style solid) (fgcolor (color-rgba 0.000000 0.000000 0.000000 1.000000)) (bgcolor (color-rgba 1.000000 1.000000 1.000000 1.000000)) (xspacing 10.000000) (yspacing 10.000000) (spacing-unit inches) (xoffset 0.000000) (yoffset 0.000000) (offset-unit inches)  9Ci!? "     7%$#gimp-text-layer(markup "i") (font "Sans-serif") (font-size 62.000000) (font-size-unit pixels) (antialias yes) (language "en-us") (base-direction ltr) (color (color-rgb 0.000000 0.000000 0.000000)) (justify left) (box-mode fixed) (box-width 57.000000) (box-height 67.000000) (box-unit pixels) (hinting yes) y9C y9C i[F0P.-s- , , ,v-.T0N$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$[0. - , + + , - .0 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . [B0P.-u, , , -w-.U0I////////////////////////////////[!0FF.!"-,++,-$%.LK0$#[.[.[.[.[.[.[.[.[.[.[.[.[.[.[.[.[.[.[.[.[.[.[.[.[.[.[.[.[.[.[.[.[! Pasted Layer!? "     %$#  %X%d  %(%0%@%P6r.` +$~(m&,$8"3 a+\ !+"@$S%^&e'_(V)C*,+,,^-+./ a/ !0 . 2'¤X8%ٝD:#S"D5 i ""q=*8is@>@l j"  %{ B5 Z p!!!!utuvy{}.tuy| +tu{(tuz&tw}$tx~"tx tu~t{twt|!tu"tw#tz%tu|&t}'t~(t~)tu|*t{+ty,tw,tu-tu~.ty/ tv/ tu~0 tx1 tu/ tz)|ywvtu&~zut{$|utu"|ut{"vtu!|ty ytuxtvxt|ytu{twt{vtu{tuutxzt|utu|tuvtv tx{ tzw t|u t~utu} tu{!ty!tw!twtqeYLE>8<.jE 6+l@6(h:6&~F6$q86"p76 y86E6c76@ 6m7!6T#6B$6:%67&67'67(67)68*6>+6J,6b-67-6:.6 R/6 ~06 <06 a.6;D: 7'6:` S%6;m7#6HR"6>7!6f\ 6786@r6B@6@767d64=6e6@p65G6N8646Iu6U65@6a:6 64 6C 6d!s65z h65 ]64 R64 L64μD5 ӱ{"0 ԡI-ڜ5*d({&y$^"* t"K!u"#$%&'(})]*2*+,K,-I-,W$=f%j"J}<+"j #&W&0b*66Nr 65} _6NrN6o!} 6h`N 6` 6N 6S 76G :67!>62 @63??t??m!i!n!x!!!!s!\& DO ' !8  n?ӹ O Ӊ>% ! >0s 418 m34{4:<45m6b 7(M1b& 7O܊,<f- m˫[8u " H%$ I$H$u%%,%O&&&7&b'''M&F%4$"!L R }"'$/&")c+y/] 34ptuv tuv tuw!tw!tx tuz tu| tu~!t~u t|u tzy tw} tv tuytu~ut|} {zutx xu-tu }u/tu u1t| w2tw ~3tux4t{u4tv~5tuz6tyv6tuu tz{yutz~ tvzutuy tzwt{u t~xutu tu{vtz| tw~zxvtuw t{" twu t~$ tu{ tu$tw%t|%t%tu&ty&t~&tu&tv'tz't~'t{'tz&ty$tw#tu~"tuz tvtz tu~"tw~$tw~&tv}(tuz+tvz.tux{ 2tuvy{|~tG62 B64 F62 K63 Q64 [65 g65!r6t!6Z 68 64 865y >6IU64 u6j 6h 8 6h,F 60p 6h1 62=6r3e6476N4B6r6u66866_6N76r 6?V6 6^76 r6jX66hN6V86 6Uzg6 !6:E< Rr$6 N$6 %6%6h%6&6&6r&6N&6'6'6r'68&6>%6H$6^#6x7!6F 6m76M6 =6"w:6$x=6&J6)l<6+nB6.kG7 63qdXKB<7;^ d ` X M!5 . <* b   ) n} I9&,j@*}M86/8&Jw G5 "[(# p%]  ;f'-D--",i++"*Q)('&"%.$5#."&! j5 =!o#%&ԃ)V+ r.śS1ʶq&tuv tuv tuu tvv tvu twu tyu t|!t~u t~ tv{ tzytuwtuut|utu~tzztuvt{tw|twtu|ty~ty wtz utuz!ztu~!utx"|tu~#vtw}%|tuz&utvxz})|t.ut.yt-~t,vt,zt+~t*ut)xt)zt(|t'~t&~ut%~ut$~ut#|ut"{ut xtvt|utx t|u!tv#tw%tyu&t~x)t{u+t |w.t }yu1t~}|ywutA62 A63 A62 @63!>62 :68 76G 6T {6d \6s!>65 765 t64B676XY6v765[6476TH65zm6576H:65yB64B6Z>64}7 6F^"6|8"6?~@$6}h8%6@ _8'65.6L-64-6i,6A+65+6l*6P)6<(65'64&65v&6o%6o$6r#6|!67 6D6]67~6T 6`1@HUam{??t??ttt@A isort-6.0.1/art/logo_5.png0000644000000000000000000012433213615410400012263 0ustar00PNG  IHDRz0[zTXtRaw profile type exifxڥi#)s988qGʬʜnO%C|y"S E[_eC^S,/CQxS>^;NyO b^Hw B{,ߑ;ry =ܤjMZ$V҈Ds{ sSf?ɳWx̜s)c \y|c]Gx,[o_h~[=#r,?O~QLF糺Y*KEXb Yx*{ v٤⎋N# )$K3ݐfE4Ew!'Ou.J#ɗ)Q7|޸㍷SgdK*W9qRJEH}$X왆g_9 xZfR/̝θ>X9OyXj_02IA)k)6$h%Yd 1I)9WrC0t7-sEs$+$Y(Jf-ZiסZVkVZms/]{>22hv}1'cN5J$6R}\%}uM]Hd\#@T>$p!)Мl V68Q%]tn̄4PVEX,(ɶ%U5}M'% jrP!Uyt*ھehMm 88Z`ӡ$Y u<`s\3rmT)\$?ʸ(^kBd: T]:>|i 8A  RB蟨 I^$7@ou@Ҿ@ o3βZ+d*:®t >yΓɀ,BJ h)=@)uT4QTtU9%A$x-*솁;80bJ6U@=?)k* "\zZG :GЦ钺Z ?f[p'w^h5g9>0L,`nh6r .Ƒ_Yq?ܙ$7}EI,ڈa:pHHڌ5XM"ZXЀ){LԸ:a@ !܅SrYb]2j0M7DĻi8CA/jɶ]#BBfnaF;), B 8}.NF3WhًZ8Ĭ=HUe ( ==2.a~: *ƬR72: Y:= QtL'^VT?KDPAPN& uNpC#\Z,璔@LVGq aa=/[J')4AR@K tzU>:ވ7Đ%WrT0")E\Zcts7:2bA4Pf)>NLs]$G$@UOnBV:1 z$߅F}w ;@G᎑hCod s@Dr%tu $G@L C7P ,v4wP6a;lsh2Ia&~}7JzȯF5 >WFYVG/.Z Y.,a}jWRq(C3k)Rlr2KS4) |Ec}\BrG(nё8{p&FH`2^K5he*,b` ͅ5N< M_luٜ`| ؅PMI/V7"EXKLPej@"}q-`JTP\u|>viG݋~8ߌs^wt;d:z!ˆrd&A@|~.AS3/%#oM03F "q PIe 1Dwzޒhwh58SOBs]Gq{6q7pZ#D%z!07jD|txy<\r\U:bё.(K]^&he(M=,u~ݗ'%)Df߃DecNA(!Ptdosvl1 "R!7۵t2TVeoyv׷%A gV򈯠;D Vqwn-<` 6]m*~[I5 yRohwF.Ь;4O3p IzŎm⺭){0dȦJAB7[g뭵 K]oC`Dk>3~mr]bKGDC pHYs  tIME&.WtEXtCommentCreated with GIMPW IDATxwչ93I^{/` fm1B z pSIKI(~Ini\zIL(wcq/nתϜޢժ~޼WH9gysDw_ B!R2(,B!BB!BB!BB!BB!BB!BEB!BHaccB!T,2B#B!8.[LPv)zB!ؑʚG#B!$rGLnR(zB!d(tsi>!B!XŮpDP(zB!\h#zWG#B!$Y1i~dXErQ!B)bW"(R>EB!P2!xBBYo"۔=!BD#o (GH2eG!B(y]J(uY /Q(zB!K1eDnɚeS({=B!Bɋ'y/%F\j&u2Q(zB!G^b_rR(zB!8_O !x2ʟ!BDi"Į%Q(zB!" ɋ/xOINIE)~G#B!Md%m0m=_7/EtK({G!B&-y2HKP=|OУo.| eQ=!B)=[1%/J/Bet#EF"JRt(HlS(zB!KDq:{([Q"M#=B!RbHɋ%xN2mU)u:!u^,R!BHqD)H^^̩DT1='#x"IK`wG!BJGelEMBbDJwHlL^_J=Eed7E{BtFt~|gQ=!B)Q\dtNv!Fp c4'T6!$O38J{7I5 %|NP(zb3Ը #08,!"\ŋ:e T7 &j(x;AR`8 LiY9R$ QtVlZ-B}ޢt}ETaC!E!LVxom nԷɴp 8KEѣQ)4T1U<= v!s/W!x8E_VEEt٩ x=6_M!yQEB 1čb$2^|J:39F9`cTyBs@V)A幏B g[bSlkYh uRCED4]+!} E@!ͶC8xhLiuD!(aԪe 264)2{ߪس'z{<ܻDEґ¼p#*."sEH+]H@[ЁC!{DGB6y ]vޑovpuD!7k0Y{?—CCqp,.֍WA<<"cSN"٣mPTȖ}idN {%ѼBH&Yy o dBH@uT}UWqsx gtZbnO0BD׿B[#"Q(%7 oŐdnG#$lt[dauC!$ Qnw }1J[`ݮ2^&k3 -mV!Ln.x.u Jbɋ#|Bt1ʧ!K^j)4>!91&VHWFn\gTn!@|،iˋޠcm ` Fɦ'#}B{qb+xgńGoB_z,M&OR(\6T}4wg -Ť܎ɁV5!!HE--R!vqhE|x+uin} 3B!t5w2*ywCL($PuʒHٌF_`tEHSOyݥ,a$Q6Q(z߂Z1DD o'S|<̣n/Q2E@HW/2?;U:{y%}؎{VW| !`#B"LʬE$ڼAtK uWOkJUlDoS(zk?؃K ǍIPIݴuf,\[B@R!P;Qd+qBNJ Qt͞'JZD/Q)VLw»w|WLGè2/åk0T4hlq@Aq/m{ :ˑBHp;Iҁ~JfC[F!n=+V9Z E>$?!ߥ)ŽM&DlFJ^J ǶG!BHjBr"[?݊&^r?XJHvD"=B!2V[7Tw"o&=B!Rrݓ=ksIوzloI0eB3(=O;!B ˌгQO-۔:B#B!(t1$X665N#k@Ѝz֤="G#B!$F5Y{#m̟(j=B!$`bڂJ +nSQ.p 7: ? `%5X0`eh8`Ū{f9J^)YSF~kת:QEqS)R܄P! l8I=q^P?ChN*P wLs–&ݡfIJP0+f#Ґ?EƮeQp[ѦSH9*B#RT?w$m;R?A <9i JCC;B24 OaX9+ PiYr nO0eS(xG!¥noZ8HHEhK0D[:D94;J#$ G^UThjDcf%P)Kٰr8YI:dS~&_ TIj Ni N ᅆ D6 4ZCT)iQz5}#jah*fKזbm,*p-g+hrI2լAR+NiB? C&auVNw|SА^U{1C-kU؆mt5\<0,C藵Ț6'tB#dq`mƪ1X.(6gg7TKKѶ&ܤڇpHшp</fUՑ|Xf~gV)^k;)}kۆb;obEN!4dMtє:=Kt%H_BROOBTQdO݉nmB XjVk%De; 3pPWo'į&i @MnJA[CIER(uf\@Q]*l9x0TGً [UD{(:m)~-%Y:Z62Vbnz}+Nbj䟲[ʕu`6#j겣2k4fId2m)G3Rq&FƢ4([p AqF*<`lƷ!K{_Q;Gq8\- `:~_f;G͸XRT堟e/q%xھ9[O]lŤlf#y Oה2qD WeBCx(4"͑4Λmz_m]%/yDf۟pRd<^}[/{//js"ydϱu)F ;doY`eZ;"@Rd$PWfZײIK^deBH8?£ο`/vq~v˞[!St$BAp⎲(SJ-5?wsma<({N݀[pΓtѯڵ&j>GGG#^R'M?pH˸vɞ"L~o<9輰 ?f۟7q Ж? kk돸T{8){V݄;_t2#Rad{rxR&xPEk&ia&|/_m\*uiV(V$2 .weIbG^杆 SP*3DY@]y}p[魝EQ(z.yx!6Fقۡ[C.>ъ{EraqʞPUh+{埈ܩS`m p.y kTB'-ȑX%>!Jމ6m$NK2W;_%W>)G `?|mu]Q5$ҕRŒQܡSj`1ʶ ?xa*lE,fGE:zɎ*#WIB cx}Xed.8W7K%;NELxAq}/^7L2u7]{;Tè^w?Qd/ J&W@Kxf,Lpe?dH(G)Yj~g utR%p{G9Wګ"ޫl_VMxC lte/6Җi־z}#P&pE T9Pd6gբM.J]uDeCh…ER X0QV$h}O:f7W+yH<Ǔ#dըLav2[!m4ъ < %BBJ>0BodoVQ}2gf&E W9FFyijRhͱ5`vӏS[ƤdO*~IF4F=S2eϭIBd)b6/b>!(῵y"I@0K:i 8wcax(Tڧ, ީ˾)7̀=K/рCzEHݤ/e!m3)JG)r QGHH5 /bejw;HPDĝE'/;nw1!4ъSwpsK)Z\5n-4+("ex/&m3Iy%!} P!qzWv x?w}ǫ!Lcccm+Ň2! 4Wfdqk-EqmMu%|2r!c#f(q7-F(z>sܤO %qEE$yeJ]>9@B`*k;!$߶/eek7MWDsY;^̰(pA=e/R)`ɺ^0UK:G+Dl,BH7CG]Em */9p% ˥2`E |0S63_Vcgh2퟊G*R3E<^|2"bER@ )IB'I-"2.l gE oI)z# W䑠1STr.?1V߉,,&wI/?^" .c?+3|SC~D1mEiw###{7"\x( ^4!/#G٣B0mV\{{QQE /W,$p:V25,f&(Yp'pp: ( j#Sn:ܤ{ԵGD/!+– "ewH_O$,B-i9yv 1]VܦU76O:J^Hu:EXp`[$<= ʲc P'CN$dۉ.9C[=yɓ1QD3ES&!~/|QEJ{=BHqʹQ TJ IDAT[H l;k7e_B9qE`&~럌M"YQhPe떕6k:\/^g3f e4!;EI_JQ8E?&j1Ѩ gʆ*m(2*' ;, †^!j*6bcO(ORcSƂͣ2ܞ#=  'N &8Cz2W{D,H?*}q|352G#ٶe=%osh .* ph* ӱ$4ObL|j Z`Ӑ&LmFyݰHe2#yzK+GY󔨴Fɖ>"{a)ޤ$D$T-~mr OHRr||7%}H_c P0j\%ц8阱8.>OokI) __%I٣B~57$F3}׆?E:6x,G%a8Sfj1ZݍUI}|sI #ި6QM2r(8&EΩJ2yֵ2~ ?.؅57/1%u8[x/lZ DG٣B(q\Aaa?Ƕ< "`C߅#8Uf%iV1FY>;27/ _u X4jRÞ@$ʹ",P Ɯ#p1#p1~|z}%ufm"2}({=BHߺ4[) NS?7%W!pP08bQ=)7δc椒)/z/$.t'?UaD/'\w"]0YwWJljS _{J!uQ(z5ggA`p bm7&abp:)~XۥFMazE Lm@ X㟇$\Grx4Ws&ck z;/B̻Ebrv﷗6>BHHxsF)!0Cɢ5ڶi.Dwgt2BR"ˑt'0(6s?#Q@? |Ԇ9ν :> ]d.2yİ=wwP!)jWc,P<,Ԡԍy)AM`+!I*^_E9j}I48ꝋM+ {Y' ;YPypÅõG$]bZdG# _B‹8(a z{Wqhå" 1Iվ,l;X۶-xjX$'zȟp#_t# 3BS^Q!zE4;a`8f]@Qv Nm 9SlҚ4W%:u(nxm . %8TR mGJKQ6wqJ% e?xO!x|qR ]]d^ߪ!{GMFȟr}X(zc*9ǪxU1ęq1ߚuY;wXd[` 1}]`Oh:ð:4kMʄъWLi9K$J3\E+ O'i@aDx5Xrx|i`5.!1/ovw))됼#1G#dfr1}%)aS8=8?OdNSZs\̺NԪEHP* ,H/\SVROo"^.߼OOOtoL]\xk|>ăpN!$CB\,02$|cx_ʌ7*іgUtm7+Hjra/F( xv雉굿.{7^؀wV/=׎܏+!em ~@@BД, BP(USk* ݮa048\NNU)]l[py9^#q$jLBR  )ʒATe'~R7~ ? `[C%r+zN׳btQ莹#d*5L.a)|'{}Ź?gO =M @3=hlqɋf7շaoz!G`{.2#9prP\T[XBM-:űWc{玮 J#F 'fB2z,Մ7vBdA#yB_&2uiJT՛;?X7OSCjQ[?#_ .۠#i()G,cvV71 >'po< m?m(9 >YÛxϗ s>|q| dY~m+ qESqS?^ ;M>jV{G|OK D|?%{.3 x@Zeʙq8yp- c.O7Xҿ[S. z glsP!]eœmQߐ= 3Ӻ/8m\R\)ciP?"GHl gL kwF$$¬gW1t-R! .*c,Gye#yy#VB OCF7_aòĔzg$۬]a2,W;Uj&ʖ9gA.$"wJ%BI[I=e/p tNi7}q?qzRy @/cW+ppk#17bK T {@y<!= ȘF=B$qx̚8C xG4Jw×piCԜO ^I*WB(E2K\]ʔH$o2b>-hGD>?<3~6pEWqQ_7oN+!~9+e?E[ ?(բy}((mmJSNEE"*Q-h`&a)%7 _>><>ԜkPrT/4! SǷb',4BhkL@-:‡S I]F…OdAz_^Fm둦88 WB|}H5' BG#d 8Svd7ÕJEr.wIׇx0 驦ѽ3L%xE;7>wD? TsNeF(zCqrSB1}vQF b -Ǎ ?9 ѽxS=RY8SO8%b_ _έ}zQUqىzᗽ^0ڟ,=BHFY[|WbO$T,0>@H/<痱A穭g1^}mUEPTq4E= HBbGDn fzV7}{<()=R9!\k7l;OJ WO*=BHY=3Y0.SܬL3򜏁YlĜߗK$eg'i038E*ywZX^r d/Ƌ/[R"I`d2RzHzr??#{Up$I#dZ\v޲A,?BbʹEgJ3}S*QwW`V(}*B9nrYRْ>!2PCL0҈'(#HtIɞۊ[^o.DΘK30c s!Mp_lt1V`|I/dV1/!pmgImxX`U͝hq XB`(o#GLQ"d(JE2Kf.Ds PCbnϭ͸q>0dt|ktoTfiZ[^,6$9_|ˬeEmw UP-yKom F8K=瓥Kl+Fp|[j3J4)KR *]3ǍX&_0LbG_g-s|AWD? LߤB Z\ _^6ڶ$)-~=CvJ_YꪜS;bU<1V=Pڜe3a3h◊EDb^hGOpǖ9gÔq1TzXBH/Zx7~ `P'6#s^ צԟclʼn-Fc+-)!Y_~ڒ<ˊ&zf򻓓>9`uN"|]tͳw䲂ǟ\WMc,?]֒N;-^5!9'$mw 䛌˴]8GǩksWg$/)'4[p0Ȅ"%0݆6\`5MCEL\֢j jVhvl[^v#9q=6\=R+l/v_ѭ|6:vQq 1qU5]."%M~A#TD`$`u.vbm'ƨQ 0A/7d(ԇ[WIk&P"e>@ۃ Ķ<4$6q/rvYU0s<3}=BH, âP[ aa0azSO0U5Oi.$0'I_ǾcK;d3\,Hc9y^(rL ۠cj7n2>)}EiI˟)|1eOȮpד@l=?'he*N^wtT{DXM!)"lv<_'p+ؗ>h2I樤o|3)yjvc!yLA*~, dFۜOuQҗKCϨ^niۍZ1%vJP!tQuRFQHWCŽ *a~sczxxܪURXx385he앰'{=ŐδΠ7mðHF(zANBU&+R]/&pPm_QhxFY,, LGh(O Ӳ"B\H\f}hȉg1.lɎKK 9!EZmI{Rd9|iozCyn^2!^j ]} ѻ!KǿBTjC!pc9g\msĴc9k:G@8v~=HuSr'B|z#|^:&TG 4pZh=Ju!)T|:N t.R&8"{Cc7y(^\x4#rt | 8.Q&V7%_X8%/ѥyҐx60 78qfp=ögX|*9OI^ʟD=|0Hx&7P[s9`W=(}S7 !$beV۲o KPMr2X[fHNunvm¥/t<`O[fcQp_k "cO#23q\A5Ă03^;̣Yh6ʬ"7gxe/iqZ;Ԃ[Uj0ַe:t=BH ?26cp ᆖ1@bYӫQ\92tlMHabmKֶmn#Qp:^3s }3 8N]GIC:hTĩM‚]݈)FLp)K>㱞i%}_Hym9=rw8X=BH2[u(v+{XIK;޲zB 蟋s;P a8]ieb)jF`9;BͪZ˅maNX0YqcҊjFٶc)ƓYx]2'ldb 7Na N˦+>¤8Ͱ[?Ov>ZGJT 嵪@UYC#*c/_0ߩ9 3p ?ӏXft{%Xe'j=/e!Y)!PMOk~*ӗ`(940J|цipp#kmDϰ4moILQ}6.bƁG'!$|C߆0D# #K'1&-<䝍OXdjd%$F DBfhE,yL[H .=V݄/:Ž8]BD/mp& -^fB5QR>q[x5["Ŗ$%ce^_`*8Y? ɱE$U1"nP<<ɰAB̯"RMv=BH!J|-J^ԇŢ^ L @Kx^_.p4hW2gco7˞]V&+$ZHTaY!]ۏ/\H2+n`j L|Ye,>Ls @j!q:v,řѽg "%|͒7(z}p/jPR 1Ze}(D?35h3 шInD s4!+ W)z,BH.%# ? >F1Զ5?ΔMr~靏(51̶8_*8"b_́Ki"d&18 EB 53ؼ,[+"Rǃ d5T.*zw8x:ĕj +d"dRe(zt Hgu}LSVFR9%CAz&0w*h0JQB߅:r- 4=BH^%輮arZ^KH–x{6- 52D#_sNO誒5nEcEG L *;e~Oٓ*J$⫾, =m9ddo ;èdto6.ʵlAC5EBt*H;vҋfÞ){2_!I6bn\EȒѶpU־8^l}^(ӵoebo #z=BHNqD^ `m;+$m;yg=*K Ӳm-9db`n69PK b#ICEѡfp"G!# hX@U\lu3G%ogp&NJIK9Ve ŊY<%N2 A= x+0yWlBH P-G5iR*+uZWaok[?xg1Gzőޗ9.Edzxб\(/k+XVkwHS&+!$k`OzIĬ;ԿmM`(\ SįCžq4IV&hKwg_" TǁYx-0Kqwcix%%c@wQ -m>e%zB*{ ǣsƙ ? /umuk΋!+q, A47Ie+ȺOÞ }Y-6Y;;agF7$!!D`0;$N)vv|wĉKĽb;х e=23{y ܹsiI ^<~ \NDO=̼[w3{_s-/A&BiD{yN~I™͵`y~$rX5w塺4Q Wᓶ& ]! O2KCP"vSu7-A|᰷U)8ChYtEaDqw͍|ñgx=\BpIv!rmmjc5uU6u7 }E"z ' /P'$Rp9*^FvzW?͏+β6ftrNpO֍ae?u,dio_/7r=7]90¨t;?祝 w}}G#Z#_SDOn=Uw7;JKQxvhszõVaSN9 669/g'm =|FMB/F&#x˕#NQG(](Cy?Ͼ&rH#akSEj'塂 .{$ai>!tT PxI%5Ft3[+.DA1;/P̵u4K]UC~+0'F񺹀7quxP^R^[n|nj*TQ7k:|޸N^d+H:(yzZ_@?Vzt)TA$_={vj4,`^[ WuSxçTyGsʖ Bmy\a=u>v$Ok߿7y6QC膇Y+>VM=AzG)8E)LTxF=ܙ}~^G9ui wqu-Uio>Yq=\G6(>r+0tn2ò杄Jǽ#YtviK'*d ^\}J{Z{dwXUV`vby"z 8.~3[aI=.DaO#SH*NX -7y5. '74VoqPg-a8b Ҥʍ\6Fk;}}g IK*9}DUO_ty-\S baPxO99?9W)ڞ=,xt$n .o:Xv{cy݈HQk!+\8L3rɶ 5o#n*z cw/zeV[x͕kcP&ko"TNpՀ쪎^wv b:Rd:PNq $/Po^}Nanrn5_Yצ9.sl'ޙZKyy]|n'Y[ȝ  $S/Z/I }ggJa궯y5z^Y鋙 Myڐ x~  KP3u.¤:.u&:hߋ{N^3k.}ZC(+h=cY$'\Yl:3"z  Bw[Cс%/"|M-|C |Ώ Ώ5;V;Jty1"Ji-#&~B"C:EAA%Ϗ ~+_h~*gĥBu<ݼ'no{i]ڼ -{T;rIyIzsLR  lw~ťfaW/s&lk:- ] u~&GϜ>=TǪgzZKĭߜίa\S[>I Л)'  > wkC+'895@Z`$?m-ܵ +tg^huI׏0ݸK*%GRjn8V~~AA@3QQmfScgSܷs^Y|';Z"U+jzB2tǯ?}6rSZK^7m&~,T@?G2J󻥩!","z  B]@dR ˻ ޢ/Ya7.pԥ|)x>=Ay;8m;zSBSt $ I7L[^ϟmܣ)y"z  B/w@OmEӖWAV$?/Ǧ{ygMﶷq=y}<k&v}X5bi\Ҿf:ڛש)"'  e*DPK@#2<>`C6UQ#:$!IՃ I u{X zV`Vڼ`NDOAAKvxz{ccX<38vr/wM%zB׎ pFrJH_bcT,%'\& >ODOAAbQ/$m{괟y3Mp2RG:fU!v]EE[-g= &Xʟy`W $wM'홃rhv[[xp!~`<=AA RBJ|@&Qp U/>Cl;Xg;jXUf=t| G+̈́lE>Һ9¹y"z԰x42;  W|ݵZLd!#u3'w"qX)_?;;qUZ[oئ!\3<1yJ'׮FeWmzTo^'#'  ]|Mu}F|L1Yȇ/SMYE%%UVqdU젋}fxkgn~(H`@Z+yg7(PDOAA.75,.vF+y)|"z  BuBŎ/^cog&~{ڝ'  }MNKh}埿=/5mu`^  =!k>^WxǾjLPM`@AAhw T4:Z3qH sڥ0NJ:݇RZlɼK_H  e2זkhF 3'1DpϤ.g랥 ><c;?C5EDAA D􂑽N&4?ߞVXlD-{?@AA@[y`s-^ӭ^9ߜǥ)ʜ]6ƒߦȖRJ@d=AA^ WZV6EgE IDATy\:$aasm{7Ң<;SB)''  - ԫHt[>zq߽)2yL6rRɲYD BTvVo3XQf/x~ivUM<=AA<d/N3L\>1e02;/}mA>xmԁzZ ^k Ћ_T'''   ЫI(64cTvRH/`u0)dz'7(񘚛I FK^нx"y"z  B_e5>{ZKM"_<٩qd9Nhdϡ,zgvښ Ak3/DAAD=?PZK_eDqDg@J ѤF9냫yj@yU1Nsx) Nά:DDAA=_ZXLaf.ΉcLX'FAblDOSKuM-*)*hqOT|_̭$-/w/qҋ''  \i׾>LHIp0.9Gn#"J݆na`M,f,&dB)0h60 Caxp<܍;].ꩬqRY+YTb9jWZ]O$H  ݋j)MC~_άL >+wk<-|ϗdh5dY5΍[K A ^ DDAA F}Y_ᣙFnN/*{TEObpRBs<kDAAHDE?;#}*6t_ZF/ B:K|,''  \q>ڑ>ww@v(vJ+] H  p>O5;K>J Fگc$wVMs Hޅٹ4# 1)_AN&yX"3( .E,-K{@{XM}=%~mN6*ZQ`NODOO2ì.ІVyj26,cˌ&/KJYq*"\P%1grfbŎG&mHLrw=: HZȟM՛&#X P'w"x"z)Օ#N6n7\ gD tfǃL"GywY^D -:3Y'zZ_ (~ LNu{܆SCqy1;[Â;ƃ(/)̙yqܝ |j:2%sDEȒz4;79˪}(Yb)ƎHyI 'B99UuʂecӸ*'0h8KɝAW:,\=69iǪ(,cROohOBNK'3¤8I8 0܏__ys.u3w ND#Y1uTr Rǚخ)i%uTu9COgAF,IQaJ+Oq!Ӫˮz04&ǒaN'ˣ܊[˩rʼ F׍OgIq<9JLǯJ/Sgi7#owǷ"w"zBp7X;  fݶ<ǙJ [4v,>*uX)tO≆1aD,UȾ-q`jL$FnÞ74WZ4[ADQz! |1qpi\Fm#Ƕ3AũaR 7}kYdV7򣉹x]x̬Xy3_<"&`Ԁ8n]0$򓵼a͞ԟ{Fd8t2OUu1 WeAVJ._C`c\>XEYOC$.;l.;g|O^tiџg3."խ&shɳx ļ+ 88b Ɔ:3]?fStunXOm¯.% >oŭWbǁ9Rx|U᫹C7xq)i=Иt?24\<(\v<'67 Nǂ],-mՠ1)^?ߏ!VR\@Mf%&.d1u& 7`[m(zy2y ̼fKRxjJ*8=6RVVȝp_,OMn##4.)ʫ4NlDDo1T nⱛxxh\4X"$E1Q#A{ov⮛I*لj&-6;U5'?ۨ3 5ζ:'/B ꝇb){Jt\89Y $12uqRfA4Xӥ|#l7[0ZH;֕9a_j+k`a f[q}1cLg]3nˎ Q&Y*[Rb{޼T-i_yF0?* ц6q7ytX> x|)-9,\55{1!<7̽/q3h~J?$Ϭ(ʺmŬSc^UػMpu_$bʌl~;kCf's|od5x~^~NEZ+CY)+c6O#X}GWZFsnM[xrÓ{"MTxxO[&<,:0eCǙI7i~?ƆJ C-'."CΩ>pP:=9{c0ipx|YzP6ndo)^/jpPmꮏ?EΌz\_[+OagzTۯOf˜:rW_sM#3\  FnEDub;AiXG?oTpy+qR'XR}Wyxgv-Q^m~oJ[6Ub7ne'^GbG 5n} s 4 d[?ᇋ =YάgVIM3_㑫=sw䓮N˧2l#|W xk-|.WOi:ƥ&;U)?x }Ftgť-Refhf|3#r؜ad裼E_h14SW  jUcOJx$~`_gZH@jzr-OAQr˄OXXߗ'X~$ݫqӻ٧5v8S,'*@YňHO2vG'$LxذD AiXe21O;-g/k׼-Mb -x<_>߶>ZG"z}.Ƙc{[hEW&[| ~u?5g#1\~h>j[\Q^nr )qwN( iqR8WOĄ[Zrjq VvA;Փk{i53{(/Y4lWُԻp;q{;g2|c WM=1Éz67߿n60/Xh;= ĴA xq+nc&sSNu`tK>ⴴؘ>\t~patထNWiB'/f`/GpykGy2gs6'174/ yĐ:O/?NպʽiF ȠBpj 8\ĠLIp^x MY3iթ-?#/r+TSrl l;EDNɌcvgO "ޤhpQO!E"MImr&2\?f;ƾTx؝cVoVףT ijYL[8]yiM g1fAJ[%w5n~Ηl(5uPab0X<:_a6Xa5PcRDGTH5+k1$ILoh_+Rb-3vO>4A1 wݹ:3\=] 9 `T/ pW7Aa6{YypISipv^$ ŲI՛X&;4$NbŴ-ޮLaiF> ʬqxv O|0gf-f<ȶrvd!z T,s&Fj3:Mb:BTyFY=LVׁ<̀6R_WvH6^pO,[\? 9g#-GpHqX?lt|1Om"5{kрٜH^lbhB8 UfbXGIMˬl&ǹzGe؉eZaaNN2fn!]/V؞ơ=?~Aae"ͽq][ 8R6]WTxx]WEI ZTiqm+;A6jp" PF[",?:):7 B4/+V$LƂ򎋜Rf? |#>"p\( S)OGSЫS UB# jPj>=!U]QȧN&5'W.Yօ|S.50)aV'Bk)vjdK{ 9ƪhq6mb.gJj?' (t 5xywI<@},s@>|1fsx{@wbzK:*ʉa\0{X8RY`r)kp`0ڹQ]5Y!_j ^nkՅM#Ē1{|rj1OonKd-$0؟%LTC;U(;liğL}b̅,/ZIv{2ܛkXJ)Q t(, xvcg< d;S W dX`f$V WW͢e_bU!2mr/m7HOpXErŔ[bʹŅM1"zB/g'y.Ƭqi 2c4*XWqga,~Σƞͦ?4i7U*xh2< ZOdBk/i[{ܐ^YiܗQ&um;ɖ '{ QVʌ Έc@l$[ 0x㏢^ܦ'՛Je꒞z{y}-PVu6eє,ȌY80i$o]Vwb"IDAT9Zc[M˕OMGd|ZvzhPQUB;eH򸈞7jSxϝ&a$-d]K:Ll ST`' MWG:@S#FixuAL =RN=~Z 6ͪ68Q XU<) GJ8JյݙRyvl$7eeGI;nXy7V65#R6$iY;,2å{wzUZI.N\ ]8\v":oA ]OF6Hzn,bS4mǸA GxX3QˋhGx>+q/,d1Z~|". y^'N#X@ATd.! 8;6ZPmg^ Jk (X喚HiɉVC<e[hٻ{?0@/|қꝲ^XR7[Ô:4v?Fp:*0ƑJv2(6_He/7?;lx7-Ծ5Xb1OI->! JʗV:Wh07o<<.'Tz~aoiZ#P nbrvrֶ3EԾ16EN$o WP\v V4f altqgV|ux?ǻE;ZIr$IIj07#fH+ 4.^̧b/Rs_GkJcޖVRGX +kEN(f>G<3?hNTfɱN?*12npVL~m^*fZwQ'uUu_8$ ^O8;ifr6{M(<wt$K)_3oBGX]zc~ yM-=[LL}~ ^q7 黓frGR }GD˸ŵ14`"#%"H̟?l2zc_ Sfp;e#-y|ҫ}l7{|QEmh,|S!$75=BfR(d2aQ?Xsd{qHkgp7W8l8]yiMZҖёs z:g: E^e"hˍv; Dd[:/:wS-<̌7q1a"'Ȅ8w ,K|ieFkIkQ^>p:*04fF]#skcX0#qY 7掵_<[KxT 4fi ֬adl?e?h?/W֡f1y?^·Ӹ%Bよ^!R0|U\lh(4+x.0#/k~*qksy۹MnVU䚏}ʥ:Fٰ k=a3sj=7$/eMy;^;24s>]3\+MfԲtR#<,ͣUgnoK _{+R L]ox6\3Gf|=!o(h`xaTs)cn*crl)+3vw zB1+鼑wNhM (Lt枑\`]t]^0d~Lk_چ? Nn탑ݗ]sCX~_u2)t2֫/`Ye3xۓ˫޶Crqc+YbAS辘猶 7X$:n ,vO2\e\n]FLF\39 Qa P5[a,w $8K9c-i\Ɯ[b LᲉ0@|!::}<3-d`ŌћXú 3H+ rlW۴A]/qߛ~Ͻ~V b}xiQ5QUE0oDϴ-<#sF? g kݏbo U:e`7nڇIN'~ֿpfrq'x!$Ih]WQX7J VV:r_j`G<3j} m]FuYZw9[kx ^ڙG5,ͺU܂3½lB{;%`ycR~[!ŋ :}^p+Ǚ14aTeo~e<;_-+EafRʫ jLxMfbNR]_/u͐MWQ=TgeJjnnTchLCSJ6l^I0kV6쨋e0=+/ob]NZyYW2*6 vRb"p(Muf}w|-Ch) sQN_ļ!DGXZV~YC7!^\N2oó=1KWs.G\$M'Բu =cDsZm\k=\^ LۉWH;qܝnck;=s}smU'w`g<:GE\T?_oږQF&[y5sKyĠcՖ7x޾0W({ t'پ.*n?j]zfqMMimq4lG7cI!js-+mX6-۵[VX7z?7/bXٺC܏oXkCN`w߸,cXDIQg VN^y?n=@>tKCU=8uk1,}:ff4ƆCpt*4ur޹_`R|Yj,NUX|scEZC%%h'9cvZ4)ful:TλSL yR#SpSy0ìY.c0☑Iՠ 9N'-c6#fweA<Lj0"l8S=XˏΈΤa㟹w1^VRGY1y`t@yu)V┟XML\c忧Zόu'+zO~U !I'4b~d:ZN>7jͽ3mϳ<. rۧ0Xl͖H v.///[%BAselU_#"XT缵;V"C(A 9zsCn f4JVn&% :JAglf-@ +; #u #U#=7,ㅵ' H% WcU&~x8Y%EָGP-#Q  9$ǒG_fJ u  '}Csp1b%l=^MG`K`hy .[B3ٽz(EO+?(upXB@=Bz=B z5;,IENDB`isort-6.0.1/art/logo_large.png0000644000000000000000000006154113615410400013213 0ustar00PNG  IHDRz0[bKGD pHYs  tIME0(8tEXtCommentCreated with GIMPW IDATxws]zY b؍hI1'jĨ{G RTP{]`[g&1wٽm_?Ի=sS{_aQ z A@=Az z@=A@ z=A@ r'@ ܋Dt.:o'*QMyDeBNO6aoڮkiʂf7:djS ,{ժ4vwjzfjRj k#PU%9~:goS7),z@Uӗjm÷=]@P  1 %C;8I1Yz.Dz[] avk#(:A@{)^|f fcHQ$ iVL3 v@r.b:Э:n. DOy8X*k. -!&Ml;G۪i(AI8;4̙7 0_WW+zz@F+2yaF5U<+S1?BA_v#@:GQHJ zWWG`Gڤˣk(C8,1F%N~ :lC@ J ̗ǼWJ /hz,OFkbk kj&u4)j5TB|GBrUWJs˵/6T+rp˴@s41KG4ޤ> U=2-~lr[alKu{522~OmHjku[ > $taprhPj§t6#/UZu?Mo Rx:٠ӂu@Qs=|npf3S%uOZ8;okS;4h+{#_A5j{z[{Uk5ըQ\!wjz-]$uRp&8i,AJsGz=E M7 ?j7ܤ4nӤ^Zd)brcb ux3yUusdi+W앝sr%8ً!Ǹ /DMRnF ٙWAݨGwo?;ӹ@@T*=itHz^צ=[YtmhRqq~v/+;4@{n0g4v\JuXjIj`{LxP(?#W5~'3 _R^Jn*-.(*Mߥڎiz:-B9ǘ392O~?INZ{LYvz]_wݧk-0Χ,C{V:o)Cz:0>]7^)й,E'eWg{>OY5٪{KqfMQ;yU`G {5>Uz.ggum|KJ]N=O^`ZvzRʯFXFF^ Vb=EHGV_U38l-74EޥE[j׍%w {$MR_9O7tygMAF?Rc%,e4Ze-Oe@| P82Z7)ʵZl%'mgk5iwЃ2ķVZ&E+ ;ꝩa`ӿ[@-&TGaookfj0;tF̄s\ 2.z gn = ?:<2dNAȃ=E&C%wiVCw[^NWsWat0{A@NϿYtNdSw&F' *?WwHFRz'gE3]VL*q! (tC 1#OkI㵳ۺ96Ȳ9ɉz 'XqµiSb=u0rE9 Đwo"stg.ѨӺ.bdo[ڨ|]M^^Jn)zɘbcvSGTׂn}י*5#OY0=qNl_婱y\Rzo9\pc;35\S,DTWB~-Ah.hgubH_?ȸ$kwѺ˭T=Zx~cC^A ה$#}*N6i% kWk+D%f+kwl9>SEy:X<#svB)I%>}yI6M3KR "3.pIi\h kGQz+A@޲:f-)ᚒdl}%z@*Gi?"4+tA>sKHs}3YNkw(ZLկô2@׆8ԟ;4/%N.'A[>Y U:w+BDk=GBM) kO]k^H>tę/0& ;;z6q~΄+A@3:.J .p[[ I}5Jt(-G[R43]R]䟬 iY:$ZRI)d\lIR<`tLBۄ[bI˂A@aFXKpxbVФ:='` ՚5&nHNɞ YtUpNW'2y461 XXNMG |aL#Tt}eMbt(wtݵ֭bD[|GkvqX]|4FQZ'c wad!ڤ.p^W(Y2z5qUSpK5;[,\t1 ieҝs_A@RQ.'=To>CfJ;4^Q_|ݘv{z86B/$X֮eg:Nݖ8DB =Y[1 YؐՏc8|G9+IaT75_[ӝ<^PW5UwsF a5Xf/;.Fw~2 =Tff;]j~X=E)~[VHssz/)G2ff?LV_3V#f lQ_{K~~oyޒI&>͟|cRvg45;݇ڷjT,AI;QrLe@7hլ7g`n ZWڻuWFBu|}/Ջzr)}K%E h#O?R {d4w4׭_ j5.[cey[~bquEQ54{lH;b,ݕz:X*GkJ8{Y>wzM +nv?R]TW0c55՛hh_,e4&ҷ][h-D_$Nbz~JJxXÕ*zwu]0G ȗ/z<xUf&-h{IN^72YO#+1gMRڻqglt= obv*럚01 :UKޥ͞Y uux>aV^5 =yɯەBN2q P.Zx5Ch+;5șڤ`?hӽÊ9C (*Kjs1UxG.]%^Uz-i9Ion^ 2.>q5FWmkzid"f";*mU@s٧Q'4*$@Re@VRaR~v{kWnz9q~ӊ,>VaS,5Z{QiEѿ'S$jSz4;Y6e.`ycm6 MPH# ww%Z#tJV'NЍ~ښ5zY>5W"|x;nHJV rj3S/L tVĝͫtEE*koJzTZ.wh ;NYߊ<-Z-w hOn/u`d7l#է߉ZJ? Og}xQIyUQ|F˱!@v6v)L1ڥ{/ =+ \jY^VĘ; y` uyxJ3.k_`j*fuTׯPC@mSM IDAT=Ek9դ,oQ7kWQE{,?PzrD}%9meم6ЫdFK_e}n̶ ɫ^C+L&'V>d=hC=uYZWR6Vj/UfW90˭9ZEE %f󭜬Xe<mJuօ/K@^hC&V0+zKNMt>۟n9@3r˓ä(>@׍ꪦ) or5d+wl,Ob$m ,e(=@mS pw O;2h ZzWl dgY_,J;z>Q?{zо:⦋tc,+ |فX᛾u^oC9ۋNf<۷W_zY?O QxYyxN%ݚ~zjPwZtrpAFU:6yeK ïW3gYW@֥~t^j YuG ӝZ)-9ܘ^m΄KkE܆o0zϓ^o5^Adf+:Zi՝nM {<}ɾ/W Yuo/Qe֧.(ɨ%S^4]Ɛe>(=ŷ˰eER.FiVgs|-Owc/pJYxytBwArc/!Hl7hݨVjݪnEf9jcPA^v˗/Nz/i1ORM@_OWYY53݅D[V).ҬCFtlbfA @{Ֆ;ijSmZ]I5ަaڭQ NMwN ‼1=Jߏ>s YfeN>;4/y^V+Y^#i2͊_o^R?ӝP<]H[r ZiP€KܺO"I$wB*gH}L N2>b&{4.&Yufzgb\S<|NbZ婱z-yecvGzVf( rA׵ײK׳aJ}Blw+nyoӾeqrvbwV+ݵ*GK2:#EC=@yY?VgZ꧷Tٔ|nN~O2z}=ġULܠ^&G@(tYM,w菽G5?]W4kߵF)ҽ^WQBjD/HIӨJWzUb1OKO$iǜg;O~u8yF6[:ޟ4 6&|}'~Kw`]a/w"eSTu ?z4U}'wmh.k̓ ~`[ rhFȽ:$p~;Rm9~_t}O%E| lJЦ>wY仜G||X}nEjuFc4'8ONwr8{"3C tSrL n@kO<srp2˫VčzBL nyGvٷINIݛSCUG,evjt t;X+uZv\RS3A2SZ1 VctμwYԭ>Xǃu:zwQZW=+u +on_)>z܋&O;ubpF9-=q'df+tٓwS^ tz5y~E +z& QbP%BtZd*iK[x~լ;e1Z~*w֦k+TVolTzXi 4ڧn֨L< wjZi3mp ߖꦿ43ի76%חdu`?eiD)dv=.uo cM;4W-}-_#domd oqtȩWkP`Bb0ݿm]=^O¡ޒGI+`)giZ)vӑuKMo%hGFMM%e|tw>Iҋ Zߤh{,ՓBt@? Vo<Сq]n7x x=y&^"®az|/製-0< u$aDnjSMm*Чi؋tM}EhK=wl Y(FBz%9BA'*nmٞSWB1:=J&u 5&LN ="u@ܨ #r's:wCj嫟Mk+[RG{: k=+!{CW4]خ&AZzF'jzmѷ{woOcFzStKxF4 ;kAGЫr i65vf rÿK|::n{iXX1\ B't2#st5O/R'+;o%w'e('@P|!tze:yz+qK80Ct{XQDiSm-z5ۆ-?OV?a& |LMҺyD=*7̙Df;U=p1\ļwd`' v6e|- {Fiz}& /D֯KTϚ{A@g%t!N2 yGߕEaq^XACV&jz ^HScF1Wͧio/7n5q[ c㵎VHytqՀށ7u}=ypȣBtg y#L[q$:uEg̯qz&9z -ݖݱSƙA@x&v읷۸>U _z;_L'ꕤ@hCwuW(]@[ κV͟n% bcgd uM_ok 隦řEN;X5]R_Ӆ ]lcqZϰfwkV}.V|@/՟+K7ӽuCq78-Ho&F2 e<]˝TOppݓ~PI (w[FGTBQޓtc-+9:+}st[wOg*Q|ۛG@?}/Y+z_oFdfxa53 (ްgЅ繳'_+'ZMb^H7?Y/u]Y՛mEߝ (-+Ca[ԕMiRpz^̮^Zǒ@Pa's*6ẗ_ڢ 3=jR]yG8/EvFuWA<9|=觧W2]|Y=McU̯ԡz69HONz:Vػ)E.NQl0=kZD Ϸ] gʕ.'5tʭ@FwƇo$B@V/ӪH=*&Yz:ӵ2^ȯҫDfNh7џCuUhNvfД2ݕ%PR;3QfM .{xO!MP=r1=ߥ(59bх=#K?zsx-7_YR⼮>fg (u1z,9\Y ʗIv3 [Z,{9SfPJЃZI %%2C1"O0΀_ndo=Gi4y!;T7F,Ѩ|QHJfji~Cш{?jJ$Mrvp{۫UgP36xV0ݝ짷X* DžR]d ~>oIR(vvZJ-s+W<|dO=쩈5^6 JMYgdk[Ez6[wLd7=nFĤuݤ!f{jPgQQBYq\+Rz$9H/zJ򜩽n OשNco&Wi|7!Ka5.z6]~z/5ޣzkj>uڧ)&)[)I#Wa~b~^r˵-"\Js'P O^/, ֩kT CJꖗcZvk\ZFn Fk424g4c)錺N+ +v4nK-m$OSTOiH׮=;4Z1/iC-2152T[$Kj{c{<׬eGwIgKTtd{jhڣ՛hʂf֐)iڤ8Gu:Y~\;l[+9jcAIVEPꦣWWIH!5k{Fݵjӊ;t{zVkTû6M5j5ovʰ hܷZª ZJ$hˮ횱d"|࿫CjxZe*\/ԔsRѿUKtauXu:pkמZv8ߑj>灠a!yaopZ tH};Tr6uO>t$}uC쾌Nާگ IR9:=ʔV@N}[IuGϭ.8Mui/\-M-KZTS22P0:vz8@_nr^Z1F?:yNRtўgH7̨m0tə$Tzjsokߣ%w^]U붅?bKi؆w~tfN*7F~c_FA%_TޒGt 'Մ 1G9wN~{>a`^ߝpp}vcٙ|44$}ehʌiOmdږM|>e[qYFo{]ֲcuSiBp?0]2q~KznZʹ=-ۊsTQtz]38ftҘ19+빭[ۭ}<ڵ}SCtjOhԙ 耰pN[SG}ӽDߟ4L jCSǮ/M׵/~$^}ScI%_[_ڤ;~SShP'o l,]xH}*fw?N _1IKsϕhk<ڪmuA`ppGݔPȯԢZn?IjRZ 3C ѱtm#/^=% TA)i*֪imѿ1&6N >uN6uwJY/M^vV_MJwv?=TtۜstW@]i;?С>u0rtjs=WS-?쨢TN3ꨡ蚿Gp~z?O!7 [czcOBtPvyD]C>Y\vλ5H G}Tn|%SհWBAT:`ɘ2@_G*|}{lJvh뮔⩐%!TUKNU/׊'.KǶe{ٶtlu,QH6mSS?VS?{PuXbک՛]zwR}* x~SZG}]w6߮lӜi~|鑺K{W*ݨ q5yV(]{^? 3EW>ޥ;n8BJ$waPPQUږQ/ϾC;BZ;aGFwjoSHn(NQEQ(8@V<7ߨѕݶy{aF-_ӶF_17(*u5ӵR|az>1SڿiN뾥u:u9JgxKw,lGӕQ.4W] X:Ɉު2FOʍJ\;Ot<~FC{Lϵm#@+(NǑ] mO7O#J$]ۻ9wf= {oAD@։yOkkczYjVT*.FB qs=GR4M??!9;|vsu9/Llj:΋NT0՚Ͻ rnU{grЋiar^ˌ IDAT]D25x2\#pG'ôp󪙍=O12q]25Nѽq2 _1$qݔ~DϦ='0~ep/oU7kx}&ʈ2}&|VUw{4&`}l=\gRϦyLξ !<ơ9]QIx=ŜaD((*]kBwڌ 앭z:Z7+??쿬2L4zE3j:RH~3s bUL1_ L2:>,cSЪW [/xɖ5ܹg͆/QB(߈$J rZGd̬r/##:,ru՘64I?Uח7Xqݘ<׃.3/1jO@y-b_*GfW'0e47 ?ӭU|}9C1h)^kTVK*L ZUp̩e$y 2sۊ=5M<8i;S Lgۻ >ܘ [0dN~j}s_0wr.twҹ!!$ѻjv uyъ {)}V [Yi3$Lw"mۘda͝iapg%&]}N{|۫'Nh2ߌWSQP['gѱA:K[{q%&:Cn'# /Y3`7OOKZ#zv#: 9[U @) xl.]/,] $͖'8ơs˫A-.V*ElrWmSIEcDdtl-.^ު01-1RiX,4^ߛ%+7\S4f3uNٹjpC,㣰O17Lo:q,v(F27>c/NUx:=AIGyW%8`ګBM]'(2q wy91fΒ-ߘbȯF&ѼEVWkwp8mj$|'wZ+]1BHw9n&vh>JPûL7|1Иgߊ?Q/]]VoWYRA\3̊S1qL87xkT8%6 Y/YeU_cT&^#`喰. ]g͎-l/&/~X*TZ՘ f3Oߥa^/+,MXrvN? P׆ѽڳ\]=%Fδk@%mws<{麖 gZ!-U]V?&[skbEOZ{{xQ&GJ1]IJpsI/ }͉,t'3%CҀƛƆw`؎cZb0-1Y6Ĵs*xH5ԇ^eS^\W~ӟxw]MVuuUQl(GTHy탧p o({y;M޼Vf'cre2,ጩ }K;~ ]1BHw2XH= C+eKґܼ.1h vUxFxG=;^UT{ _BfنuV=gZjinK'YfzRX2%Fy^AYm "AVq2ʼ\nԹZ4n6h^隆6ej| h<4w ߷%-n]̍SG"Y)J+ʞo)UJ,9um:vn![aDJyǏ+uxSfRUjPX;hjܳTK HYur?ܽ0 gb#mj1y -ab.(Wwc'^)\wحkeVPnifiZ]5.!V+W~Q"6Ё0wUR^UMٳ;ņJswBws*)iQ$x.ۙN=s]hD@X<2ƭ8]`LWz]<^3Tcu7=T팳lg3\@xC?ӜhBQd:VBq@U}Yޚlem"w\P;7&Q潕ydgCL6nC]RKِ;dkboeՂa|uà:(1(4MFye:x1#1Akqa$M'~/oS--؍՝JbTB}m<.J*mݹ+t)a|axꆁL Gk cXڭԻ֖85ΟfƸK ǛH'}5"&XN琨UAu3s)lզ]UVZ1o-CK~"Dt0,PRs{ѐ)Yگ'skHiCgxePۖo)nsYջG"\t%eC%JW0?LZcFuɎOfns@abմ1ϫ!7`Ri_f;W\(с׷IŁl.M8# *xADpmKRAe×ƶ,Һtzܩt,=e 0oP$E1!'=)̽:WZL֬tfU[IjQqzJ#3oDrN-_LZ7:j{G(.U$bzt+򿖨07<<>qῙ_Q۸-G%\wGjbz>1`HWg8b}H9az)ԣgv3,+}0',kck.nUʏZabwQn.]$ V֣⯂ztj78cz%OVqh^V4;<4b#;T&3UO9bVրk<k{nwrhxcWݿ\ݰ$F5/ٟO`?m[=3mhD44Mâ +wi8{4Q1ppod֨f'Ȥ,7%tK'(3Vyj1 *s\ˁz>=0n-n2XN_sc󭫱`㺚7c+Gnyj &F՟adVplYLn Y>$*XS9"RpN>+K*)d\=1G;'Y×W'n4t7kw(q['sCr9^o:\m;n>aJ>dأc֠(ދ ~8{y_yć0#AJ#Tz Kaރ,Ϩ᝜pFЌ<Yy#3XK@%em^nVw6 y}bZ$3gh.69G_I/ԨuF eְ8fEkQdƳkqhZ2߹*S-k/"I '9niy-5.7,,<#a?sgr]<:5RcvtU9+(ys@&{s{'ϯQl-mz(y\J0^w# R?zPeNmێV_~XLDOx>w{FU>C}V1 C' ӏ:e`J֎hL \cAZ}}¬۹պ0.צPZɂ~Tu Kܓo]Hn Iex'x389޾crh#|?_ןAv?R'm8[5-8 ܓW`yD]ɍ,ҏe%1f:{7˩IXQ- 3O1,ĐpQ6W2hZΓW2ؑL7UŔVTix4 _b}U pr8{)?X1SzL:\ݪ$Fh#VY_gJd(nn0M s7YΎYv(9kup@>fsƯۏ#3y$?BH W+6 ~v"p(=z|zZW/G+śLW7!afڶ WO-Y|ykjC}:"U%!>>@n,) 5l[leB~t]*sD5.W.ubK#cQ]o&aL8`]aÞ}ZN8 loX=eĴIuV)e_:lM: A~5I['o7 QMY =ƲmBLK I`zG0`u*:xrCЅ z| ZnV L?Tď2+54_; A+40+Dz sxjSݔהD)+/^NehsJ6Gano~#4Ʀ0)Ÿ0AeY2KvI[ǘMct?NWċg6)! !.IDATtRTqmٕ/ny,dvۖ&\be[Ij]1w{b6dUEbaknfߧ4k8SVþSe|VhϏ V.u!I;7!19j Jzl+ Iķ e= vxY'HH':>>Csxn&C*DbB"֚::Tհ ߪAR!Bt,!1J!D5z[ sKr:&Ey'SV N;#2 HbBIh'$0nHoB).a|HB䑪uX-ZD!1J!EoIO}#cHOcGyԏBbBI(&ϧ<?OBHB!%$X!;ؗ߯-^eN>XGIvaT%ʺבsB!"!B!$zB!B!$B!B!B!BIB!BH'B! !B!DO!B!$zB!B!$B!B!B!BH'B!B=!B! !B!DO!B!$zB!B!B!BIB!Btk>gIENDB`isort-6.0.1/art/logo_large.xcf0000644000000000000000000050763113615410400013214 0ustar00gimp xcf v011z0BBUiUnnamedBCABcCi%HC/CuCJCNCJCNG gimp-commentCreated with GIMPgimp-image-grid(style solid) (fgcolor (color-rgba 0.000000 0.000000 0.000000 1.000000)) (bgcolor (color-rgba 1.000000 1.000000 1.000000 1.000000)) (xspacing 10.000000) (yspacing 10.000000) (spacing-unit inches) (xoffset 0.000000) (yoffset 0.000000) (offset-unit inches)  1hfg h"i6nFgwz0 Layer Group!? "     %$#xz0 z0CScs#3CScs#3CScs   # 3 C S c s   # 3 C S c s                                                         Lo&7z0Layer!? "     %$# z0 z0]m} -=M]m} -=M]m} -=M]m} -=M]m}                                                        Lo&7z0 Layer #2!? "     %$#z0*z0jz *:JZjz *:JZjz *:JZjz *:JZjz                                                        Lo&7  sort!? "     %$#*gimp-text-layer(markup " sort") (font "Sans-serif") (font-size 62.000000) (font-size-unit pixels) (antialias yes) (language "en-us") (base-direction ltr) (color (color-rgb 0.000000 0.000000 0.000000)) (justify left) (box-mode dynamic) (box-width 746.000000) (box-height 289.000000) (box-unit pixels) (hinting yes) 6 jeq}  !!Y!i$'J+u/34D9>4>DD~J_S\elqequsv x{~]9%5EU !!!!!!!! !!!!!!!! 76%!76%!76%!76%!76%!76%!76%!76%!76%r =;Rj  P......... P.........   . )I&$(#!lJdn q!k"X#4$ $}%@&'a'(c( )G)**U*++ -)&$"! ""#$%%''()))*++++,, -L><:87 6)mB=96&G?76$G:6"I86!Y;6F6o=6\86T7 6R"6V#6b7#6y8$6=%6J&6j'6<'6V(69(6S)6:)6^*6A*67*6Y+6E+68+6 -/[)m& ]$" }!P7^y !z"`#;$%&W&''())o)*0*~+++ //////////////////////////// 0000000000000000000000000000 .65 .65 .65 .65 .65 .65 .65 .65 .65 .65 .65 .65 .65 .65 .65 .65 .65 .65 .65 .65 .65 .65 .65 .65 .65 .65 .65 .65  D*B)D(H'B&D%H$B#D"L!E!M UNY Y! YYNYY N!Y"Y#p$ $0%0*+'U$$"] ic<!S"$'%N&b(r)y*+x,r-`. H/ $0 0 u1 D2 3 w344-I'%Q#/ *'$" !#$%&()+,,-./ 1 1 2 2 3 4556+''/M@;:98765*F=;86'fA=86$H=76"cB96 XA6cA6wD 6N9!6l?#6O8$6B&6l<'6]8(6R7)6M+6K,6L-6P.6[/6 l7/6 :06 @16 L26 l726 <36L46v746@/676a(640/.-! UN?<;%62-$Z$6/% /!Lq* I'q$g", =6y!4"z$%;'`(})*+,-p. N/ *0 1 1 S2 34E4.i'ȉ^9 =b%U w#{941 .,*(&$#!  !"#$%&&'(()**(K%>#94 1 .,*(&$#!  !#$$%&'(())*+++(&32.&96520,5 61.%1 63,"/60',63**63)(63& &6/%65)#60"65"!6* 6-6/ 61!62"61#6/$6, %6(&6&64'6. (6$(65)6- *6 *62>;7(6$xH?7%64rF9$6$_6 9ݦo14Y1 S.,1*/(&m$+#m! ,E^ h!m"a#O$3%&&'?(()))%_"  fxuMhh  Q ! c" $ 0% Y& g()::::::::::::::        " # & ());;;;;;;;;;;;;;; 862 YB<;9787 686+UB=:686"UB;6865oC;686/[@7686'\@68 6 nB 68 62 G7!68 6, `;#68 6"K%68 65|?&68 60g;'68 6(Z7(68:68:68:68:68:68:68:68:68:68:68:68:68:68:68:6 d :^*$a  0G;@  , m ! 0H#  $ %& PH' f()::::::::::::::!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!76%!76%!76%!76%!76%!76%!76%!76%!76%!76%!76%!76%!76%!76%!76%!76%!76%!76%!76%!76%!76%!76%!76%!76%!76%!76%!76%!76%!76%!76%!76%!76%!76%!76%!76%!76%!67656/)86Ks574  2n2C R0 . ,f K+,*  (~l(8.& $l#Q#" "a!!! !!!!!!!!!!!!!!!!!!!!!!!!!!4 3 2 1 0 0 0 0 0 0 M1 1 1 1E M1 1 a1 2 1 E1 1E 1 2 1 1 1S E2....................................()))))))))))))))))))))))))))....................................****************************)6%)6%)6%)6%)6%)6%)6%)6%)6%)6%)6%)6%)6%)6%)6%)6%)6%)6%)6%)6%)6%)6%)6%)6%)6%)6%)6%)6%....................\[QA7.(!  ! " #}$|%\&+%n#6" !L &  T(+Gn !!!!!! i< +*K**)<))W( (S'&7&q%$($J#_"i!f \D!l"$5&0)g,,,,,,,,,,       ,,,+++**)))'(&&%$$"" !"$&), --------z,6]60*#Q6& I6!@6* <65 :61 86+ 86, :61 <65 A6* J6 R65$ `6/(7+69+6G+6\+67*6E*6c*6<)6Y)6;(6\(6?'6u7&6N&6@%6:$6k7#6\7"6W7!6[7 6b96r=6G6!\;6"I96$E96&F=6)[?;86,B=;:7 68,68,68,68,68,68,68,68,6C+p;  E & ( H   j+<  ++t*&**b))~((u' 'F&%%-$O#i"r!k S1!N" $&i)*~, Bm )x(0' 'p&Y%Y$N#Y/"!$%')*+,-./ 0 0 1 2 2 3 3 44455566q r     k) 554443 3 0""#%'(*,,-//0 1 1 2 2 4 4 4 45656667     6666654 3 .65 65432/)"641."61,!65."$6.&6*'63")6**6/+61,62-62.6//6+ 06# 065 16, 26 260 36 361 46 46) 4645656%56056566UIFA<6W76! N6#!u6$!76%!76%!s6$!Q6# 96 D6B65QG965 67 6056%5646546* 46 362 36$ ʯlD"іJD!h $h%A' )/*T+n,v-k.O/* 0 0 12 2 2N 3 3E 444i55 5:6j6 Bl F & ( I ! ,h 95 54o4!43X 3 "K  2TMT   4 X o !!!!!!!!!!!!!q [ 7    UNP.!F!"N#%C'-+4 n3 2 :2 k1%"!#!                  !    ! ! """#%''*654 4 4 2<"60"]!65&> 61m 6.G6+86-Z6/B6376\6*G6496$x63Z6$J65<6+ 86 }765 d6. V6$!P6 I65 C65 ?63 <60 :6- 96+ 86+!96+ :6- <60 >64 C65 I6!P6!!W6'!b61 ~65 76# =61 J6 Y6,x696-G6[6276+B6#[65864I64o 65!?!6' `"6/<"65)^$63*=%65.'c(651//)) `RC>B.65776}746P46 =36 u726 Q26" p " xRJ8"8|Ly*w"w Fe} #?s c1   k O ; , % " & . > U t !  fJ A J~ khF H    / 1v +2)394y 4 4]6N"  akWj"l M ];o?  u _ +ڗg>=c3 t!;(e(  3)))1"U! e RHNfU> O  ~ 7 !!u O    !!!     R v   : OAYgSNZm ` <"W#Q%'*))(''%$#"!      !                  !###%'(+++))('I7"63i?"6"K!60 _8 6i96)r865i76 V6,E65:6\6&>61c65>6 \6$ 86* J60 d65 765 ?6!N6![6"!m6$!76%!76'!86(!86)!86*!86)!86(!76'!76%!m6#!Z6"!M6 >6 765 b64I6.86' [6 =6c64 >6+Y6"965D61T6$d765m86/c86!W763H!6&`=!65wF#6(kE8#65hF=&6(=<(64*6%)61)6(6*'62'6 3E!#& "]* +t  #3 h 7&M () "]> u-  99F8~8E6 6 B Wt+ i ]"  . M=! >=  x   R 8 #      # 9 T z  # fZ3x b` #y&A\K5Uig @!"&#f%'z* )T)("'b':) '%#"!    !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!;. +'%%$#!                                               8:68*61/-*)0 8'62,8%62% 8#65'8"618!6/8 6.86086486!86. 8686,86862 86& 86 865 864 860 86, 86+!86*!86*!86*!86*!86*!86*!86*!86*!86*!86*!86*!86*!86*!86*!86*!86*!86*!86*!86*!86*!86*!86*!86*!86*!86*!86*!86*!86*!86*!86*!86*!86*!86*!86*!86*!86*!86*!86*!86*!86*!86*9)kC '@%#)"!T FX7,R X < * " ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! !?!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! """""r"V""##~#I#$$`$%%D% &a&'h'(X)):*x* ?!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!""""""###$$$%%&&''(())*?6!76%!76%!76%!76%!76%!76%!76%!76%!76%!76%!76%!76%!76%!76%!76%!76%!76%!76%!76%!76%!76%!76%!76%!76%!76%!76%!76%!76%!76%!76%!76%!76%!76%!76%!76&!86*!860!;64!>6!F6"P6"X6"l6"76"<6"J6#]6#76#>6$U6$76$B6%^6%;6&T6&96'Q6':6(X6(>6)p76)L6*=6 2!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! !!! !!!"""S")""#s#.#$$6$%l%&& ''(|( )K)*).......................................---,,+**)('&$ "  )))))))*.......................................---,,+**)('& $ " ********)6%. ..".--5-6&-65,6),65+62*6- )6+ (6,'6.&63$ $ 6/"# 6/( 640--%656%)6%)6%)6%)6%)6%)6%)6%Z....................................9.`..-/--,z,+*c*:),(8'_&$ o " ! ˉP!| *b8l F,,,,,,,,,,,,,,,,,,,,, --------------------- 8,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,6 "Y!N YYNY BHDB H!D"C#E$I&H'I'T(I*L 2 2 1 1 0 / / .-,+*)(&%#! 3 3 3 2 1 0 0 0.-,+*)(%$#  264 26$ 163 16! 06- /64 /6".6)-6. ,60+61*6/)6-(6( &62 %6+#6/ !6/$64-#63/*6565420/$ 2p 2 1e 1 06 / / .!-?,W+b*\)G((& %C#v!_ sԴg9 0 0 =/T.f-m,s+n*h)W(;&%s$>"{ &S `"I$'G*/ @ 2 1 0//-,,+*('%%"  "$'*. @ B16 <06 u8/6b7.6W.6R-6Q,6T+6Y7)6e9(6}>'6E&6W9$6uA#6S:!6H76lB76 eB76"mC96$H>76'pB=86*D>;86.P@;:97654 @*M** *"+]++q*g)L(+'%d$%"f!( 0"#$ _'l* G. Lq @&%$#"!  !"$%')*- /25 z'&%%##"! !"$%')*-/ 25 z&6%%6- $61#63"64!65 656563616, 65'!62#6+$62 &64('65+)64*+62+- 65/' /64/+2640/( 5312.  {&%6$[#"! pG #!"?$ %''A)I*8- u/|)2ȎR5vT( z!!!!!!!!!!!!!!!!!!!!                      86*!86*!86*!86*!86*!86*!86*!86*!86*!86*!86*!86*!86*!86*!86*!86*!86*!86*!86*!86*!86* ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! +9,a--. /& 0. 1& 2 45v6Y79a;<(>= +,,-./0 1 2 3 4 679:<> +v76,Y6,H6-A6.>6/< 60= 61= 62@ 63F 64S766j<67G69a<6:N966<H9> +C,y,- ./" 0' 1" 2 3 4u6<79B:s<> )))))))))))))))(&$B! Y`*****************&$ )6%)6%)6%)6%)6%)6%)6%)6%)6%)6%)6%)6%)6%)6%)6%)6%F:'6%H>7$6%qE;"6% sE=;6%`B=;:876%/ ^ ! "@$} &/'b('1%@$Z "q } % 4> YP v^U w 6\؋#(@@@@@@@@@@@@@@@@@@@@@@@@@@@@pppp|C>!zA Layer #1!=l "     %$#zA1_1k1w1zAvO3M]m}ɍɝɭ͢~kT jz!$&)+{+++++++..$.D.d/0000000001 111"171?1G1O1W ?=<<;::9877665555555 ?=<<;::9877665 5 5 5 5 5 5  ?6=6<6<6;6:6:696867676676676576576576576576576576 ?=P<3}<h;_:?z:z9 f8E7)z7g6L61u5i5 z5}5}5}5}5}=;986 5 4 2 2 10/..--,++********=;986 5 4 2 2 10/..--,++********6=6;696866 65 64 62 62 61606/6.6.6-6-6,6%+6%+6%+6%+6%+6%+6%+6%+6%+6%+6%66%66%6=HU;)59kl8IQ6&uw:5_q4Q}k27wH2"w )1i k0 I/ u&._.}Q-w6-w,^+6+o*|*|*|*|*|*|*|*||HU|)5I:8(75l32J 1d 0n /q .k-X,4+ +}*@))a((c' 'G'&&U&%%%G%n%%%%%%%%%%%i%<%&&&K&''<((W( )S*:865 3 2 1 /.--,+**))((''&&&%%%%%$$$$$$$$$$%%%%%&&&''(())mB:G?768G:66I865Y;63F 62o= 61\8 6/T7 6.R6-V6-b76,y86+=6*J6*j6)<6)V6(96(S6':6'^6&A6&76&Y6%E6%86%z6%]6%Q6$I6$@6$<6$:6$86$86$:6$<6$A6$J6%R6%`6%76%96%G6&\6&76&E6'c6'<6(Y6(;6)\6)?67:/]~8 Av6?x5(p3 T2p 1/{ /=~ .B -=-0~,{+ p*U*,) q)C(x(G' w'8&h&~&?%c% {%"%8%N$]$i$r$x$z$z$w$q$h$[%K%5%~%y%^&:&}&b'1's(?( u);)lB&*+,-./01 1 2 3 4 5 6765 4 3 2 1 0/..%3(!"l$%J&d(n)q+k, X. 4/ 1}5"&(+, / 0 <=2A$)*+,-./01 1 2 3 4 5 6765 4 3 2 1 0/.."%&'((*-,. / 2 43AL><:876=9'6*6+6,6-6.6/60616 16 26 36 46 56 66766656 46 36 26 16 06/6.6.6%6;:8736>:9760*#G?7 6& G:"6!I8#6*Y;$65F&61o='6+\8(6,T7)61R+65V-6*b7.6 y8/65$ =26/(J=6H65456T96543256C#64226Q7&63156B)62056W8+616E-6505 6>;/612 6M163 6D=6;==6Y726A.@Sbiouxe"Xw$s!'n"(k$)s!*n"+k$,s!-n".k& /s# 0s' 1p+ 2x' 3x- 4p-5p 4p-3x- 2x' 1p- 0x- /x' .p--x-,x8+xP%ɇux"zG /]~c Av"`?x#w(p%H T%#p'}/{(}=~)$B+J=,x 0~._ {/` p2w@U6~xǶ˥#Т&촄)+-ˆ / 0 2 2 2+;U8$6]4i2c 0< / -S,*')N(b'r&y%$x#r"`!H $uDw4  I!0 Q1 " K  2TM               ;8642 0 .-+*)(&%$#""!  !!"#1 3 4 "!#!   655 4  4 3 3 2 2 1   1    ;fA=88H=766cB964XA62cA 60wD 6.N9 6-l?6+O86*B6)l<6(]86&R76%M6$K6#L6"P6"[6!l76 :6@6L6l76<6L 6v7 6@!6a"6;06 Z26 <"606 ]!65&6> 616m 6.6G6+686-6Z6/6B636766\6*69C646V86$ 6J63 6D6$ 69?65 6C96+ 6Y76 6K65 6G6. 6C6$ 6A6 69?65 6?65 06O?63 4/6<60 64/6:6- 64/696+ ;9^|84b~6My4Z2\ 0S .=z -g+=|* _)r(0{&?~%I$M#L"E"8!'} whO*~ sQ #~ i!5! r" xe" <.s! s"z n" 8 ] k$m }<s!)x%n"\vk$|xs!>}&n"g=k&}]s#<ws<n3 q @ | ` : ~ t ] ԧH r6 x/l( x8s~ xPv}  `y} D%  #%')+,. / 1 2 3 456789::;<<=(  K> i!c<S +',N- b/ r0 y1 2 x3r4`5H6$  u!D"$w$4%% I&%Q#C % !%'(+-.0 0 1 3 4 57889:;<<==>'U/*%#%(*+,-/ 0 2 3 34568899:;<<=>'=CM@;:9876532.&%F=;86520,!61.% 63,"#60'%63*'63))63& +6/,65).60/65" 16* 26- 36/ 46156266176/86, 96(:6:64;6. <6$<65=6- '6987 654 676<:987652640/.-! UN?<>;7 6=:9762-$xH?76?<96/% rF9?;7 6"XL>"6cA6B: 6wD6@?6N96;76l?*6O8+6B-6l<.6 ]8/6 R706 M26 K36L46P56[66l766: 676@!6E6L"6T6l7"6@:6<$6A6L%6D6v7%6H6@&6L6a'6R634567988986;%62-}76=<:66Z$6/% 86?<C&9HXcluy|}zwof\N@0%%C`yoS8 uT- |Y*#uE%}U'X)~N+x7,e.z7 /W 1l 2w# 3|/ 4~45~76~17}(8x9p :^:B;} Hz@e\Sց=zg =|  _ r 0{  ?~% I1 M2L3E484'}5w h!ֺO!֮ *~"֦ s$ Q% #~%i& 5&į r%|X5<#t> |X7xuMhh   Q    c  0 Y g&&&&&&&&&&(, / " """"""٤!       W6        ''''''''''),. 2 458:;=,#><1;:9 .9988777778888W862686+UB=86"UB;6865oC;686/[@7686'\@ 68 6 nB 68 62 G7 68 6, `;68 6"K68 65|?68 60g;68 6(Z768&68&68&68&68&68&68&68&68&68&68&60,8)61.%8,63," 8/60' 8"6G7 63*8"6G763)8"6G763& 8"6G76/8"6G76465)8"6G703608"6D06365"8!6/R8626B4 6.86.6G316086-6G7306486/46G764/6!86406G7664/6. 86.6G764/686-6G76306,86.56G761686036G760362 86306G76.56&86.6G765.686-6G76216586-6G76/464 86-6G7 6.6086.6G7 6256,86.5 6G76+86/5 6G76*86/4 6G76*8604 6G76*8667603 6G76*86W|26|x1P|eDn|FAm|}$W}|r  ` | X [ | 7 H} | z$p| hI| Jg| ~($v| t3}|q|&|&|&|&|&|&|&|&|&|&S8|(uT-|,|Y* |/uE |" }U|" X|"~N|"x7|"e|"ߔz7|"W |!{.|o {#|},|D|d|}|P|}|Y|)|݃x|]|B|,| ~| }| }| }| }| }| }|555555555f  4 4 4 4 4 4 4 4 4 4 4 5 5 4 4 4 3 4 4 4 4 4 4 3 4 "  u`Mڼhh Q c!0"Y#g%&==============5 5 5 5 5 5 5 5 5  # 4 4 4 4 4 4 4 4 4 4 4 5 5 4 4 4 3 4 4 4 4 4 4 3 4 4 4 &$'+/ 1 358<=576576576576576576576576576YB<;97876 676:6 46 46 46 46 46 46 46 46 46 46 46 56 56 46 46 46 36 46 46 46 46 46 46 36 46 "64/6 6987676126 6;:9864(+*)0UB;67642265oC;6b76146/[@76T76'\@6T6 nB6T62 G76T6, `; 6T6"K"6T65|?#6T60g;$6T6(Z7%6T>6T>6T>6T>6T>6T>6T>6T>6T>6T>6T>6T>6T>6T>6T>6T65}5}5}5}5}5}5}5}5} /AS_ekqvxD Hxyn H H0H H0H H0H H0H H0H H0H H0H H0H A0H V0H '1H V1H V1s V1# '1V V1 11H 2 V1A #1s s1# A1V 2 H1A 1s V* #񊝯  h s ǂ :"DnH}ϠFAmXǍ}$W}Ă r  `ǂ X [ǂ 7 H}ǂ z$p ǂ hI!ǂ Jg#ǂ ~($v$ǂ t3}% q&5555566778ց89::         5 6677777X>>>>>>>>>>>>>>>>>>>>>>>>>+        5 5 66788888888888;<<<88888886%66%66% 66% 66% 6 6% 6 6% 6 6%6 6%6 65!6 56 66667676%76%76%76%76%76%6=6%6N6%6S6%6T6,6T6.466T6.5666T6.566T6.566T6.566T6.5666T6,.6T6%6T6%6T6%6T6%6T6%765Y6.5=6.5=6.5=6.5=6.5=6.5=6.5=6.5=6.5=6.5=6.5=6.5=6.5=6.5=6.5=6.5=6.5=6.5=6.5=6.5=6.5=6.5=6.5=6.>6.>6.+6|kl|IQ|&uw:|_q|Q}k |7wH |"w ) |i k | P I  xyu& !_ }Q w6 w ^6oߍ|ډ|ه|̅|DŽ|B}>w.wp7Y ~ړ|Æ|誂||ˇx) . / 0 1 23456* *ǁ * * * 543322 1 1 0 / / * -,,+*)('&%$#"!  !!!  !#$%&( -,,+*)('&%$#"!  !!!  !#$%&( 6-6,6,6+6*6)6(6'6&6%6$6#6"6!6 6 6!6!6!6 66 6!6#6$6%6&6( xq.-x.,p),r!+r*g)h(m'` &[ %}o $ #ˏ "! }|\+n6 L!&#xC $i*%i&K(*7+q+,(-J._/i 0f 1\ 2D 35l685:0=g}<;;:98765 4 3 2 1 001 2 3 4 5 678:;;<>**+,-./01 2 3 5 68:=}<;;:98765 4 3 2 1 001 2 3 4 5 678:;;<>*u76*N6+@6,:6-k76.\76/W7 60[7 61b9 62r= 63G 65\;66I968E96:F=66=[?}6<6;6;6:6968676665 64 63 62 61 606061 62 63 64 65 6667686:6;6;6<6>6*#~*L+j,x-(}.5~/9~ 06~ 1*y 2m 3Q5'p6Ay8 Fy:5e=?}& =        2  K   <  W S7q$(>>>>>>>>>>>>>P=<:9752/3   !"ʃ>P8 3 2  2 1 1 0 00./V=<9874   !" 6K>6E632356B60369?6.56@;6136E96- 6G8640 6G7612 6G7612 6G8640 6C96- 6>;61369?6.56B6/46F63236;86K36B=;:76R726 G678::96 \6;B6 769@6 E6I6 c6Q6 <6O6 Y6I6 ;6A6\6O76?6J<6u76F<6N69;<7$6Q;>6J8>6G?6D?6B?6C?6D7>6D9>6G=?6A8>6A=7>6A<7>6@;9?6=987>6;98T6/=6-<6( :62 96+76/ 56/$264-# /653236654356 6 66 6!6"6 2 Ɲ       ߅ߌa| !7J]lrx~2 ^ : } b 1 s ? u;l#~Lx+*)('&%#" "%?|=w$l"3Hʃ .,(+(    84 0 //.-,630 686+ 6+ 96+ ]6# :6- >65 <60 m6, >64 G6 C65 860 I6 Z 6 P6!B 61 W6'7 6 b61\ 6) ~65G 64 76#9 6 =61 x 6% J6Z 60 Y6,J 65.6554432/)x6<6-64Y525 686- 69>64226}76. 6D63156d6.5 6Q620566V6.5 6><616P6/5 6E64$I6/5 6S76*C6.5 69? 6/?6.5 6H 61 6<6. 6C: 62 6T96634 6- 6F 62 6G7630 6- 6R9 6/ 6G76.6E 6+ 6G76316R9 6$5 6E86/56F 65. 6E96-6C< 61 6C:6.6J 6. 6>< 60369? 630 69? 6-6E 6. 6B 64/"640 6C 6/5#6- 6F 65.$603 6L 6/5$65. 6V 65.&6. 6C9 6.5&6/569?621'631 6D65.)6. 6J6.5)6- 6V76)UIFA<6A6- 69>6. W76B6. 6D60N6D76.5 6Q61u6F:6.5 6><6676E=6/5 6E66769A76/5 6S76s6B;.5 69?6Q6;79 6H696 H7 6C:D6lB76FB65eB76R QG965 mC967 60H>716% pB=8.6-65-6*-6,62 ,6$ x@{} w y} 8g w~ mD t~ )| m+ \_ e: |' ]O >d Qfg ~# Bz } W 3%< { !J^ 5 }qy Zr%# xZY? ~ ?`H 64 Z xvqkeXG6"# `$ q ~qĥ H | Т` ~ 촄2 񴂀VA P Q\ րke y*l ~7 t ;1 69 ~6  }(/ wV ߂lx   ߁  ݁             t!Al { 6~ },O }1# .} } % Jx xh K} `[U~ aJT} Aw4Hw x~ ~0_~1x 6\{.\ -8-|-^,,,o" 4 321 0 R/ v/ / . :. - . O- . A. . Y. / / g0 S1 N1Z2m34`<#W',& &%%$""!5432 1 0 . -,*!!# WQ Ƿ +ͱ&n1 1 1 2%76653 4 2 2 0 2 0 1 0 0 0 0 0 1 1 1 3 3 346 7'd$<;;:977653 2 1 1 .,++$&')/> %1 1 1 2<"60"8565&8461836.726+716- m16/ Z063 M06 >/6* 7.64 b/6$ I.63 8.6$ [.65 =.6+ c/6 >.65 Y/6. 9/6$ D06 T065 d7065 m8163c8260W736-H56+`= 6126+wF#65126+kE8'632465:=-645689989930&6465/&6%6.%616-%66.$6*6/4"62640"66-!6%6.56- 640616.6363464565465365 263 161 06, .65' -62,6+*62 !63464("630665+9#6/&E!64223*kER9632465.'hF=6F653 651//)) `RC>=<6DQ?76534346577 6}:H@;:97654544&6P616 16 16 26s"z@| ]|4}< |3x%}2v~1x *0}& =0= T0] m/w }.< 3.n [.3 {.q <-@ o.| 1.` n.: =.~ x/t `0] C0H .~16 &{1(+{2~5}3}P} k }Q!ڟ}N|#뺐Jb%˳& &o%*%Y#w"1"V!m z~.@ M ߤ'Tdž)T߄)Q)G )}8 (v$ &e &~E%l #|DZ c! ~% Ӝ[ N߂躋l; 3b 㾔 mL4  2Ii$D ǩ~y~ q&9IXcmvz}˻%3 s/ 0 A0 `0        ܼ~7\u O          Rv  :   O  A  Y    g S  N  Z m  ` <    %$$#""5888 , +   #        & % & % & % % % % % & %&% % ' & ' '  ' ( ( * *+,,-! 0114888''%%$#A>603 6G76*86B:603 6G76*86@?6604 6G76*86;7/4 6G76*86&1 6G76*86# 6G76*86"6G763 6*86 6G7626*86 6|76.6*86586-6*86486/46*86.86406*86'86.6*86 86-6*8686.56*864 86036*86+J686306*86"d686.6*8657686-6*861?6M86-6*86$ N6G76-6*865 [6G76.6*86/ m6G76.56*86! 76G76/56*863 76G76/46*86& 86G76046*865 86G76036*86( 86G76036*8665 86G76036*866( 86G76046*866 76G76/46*86676G76/56*866m6G76.56*866Z6G76.6*866M6G76-6*866 >6G76-6*866 76G76.6*866 b6G765/6*866 I6G76216*866 86G76/46*866 [6G76.6*866 =6G76-6*866 c 6G765.6*866 > 6G76126*866 Y 6G76.6*866 9 6G76-6*866D 6G76406*866T 6G76.56*866d7 6G76- 6*866m8 6G7631 6*866c86G76. 6*866W76G7 65. 6*866H6G7 6/5 6*866`=6G7 6. 6*866wF6G7 603 6*86686G7 6- 6*86G7 603 6*86G7 65. 6*8%6%8$618$68#6*8"628"686 }| }| ց}| }|~/Vs }|r:Vs}|j A` }|^ 'Vs }|P  }|A| }|-| }|~| }|{| }|g| }|M| }|0| }|}| }|j,V:| }|I}sV/|}|~!ksZ}|qR }|J < }|~ )}|f ~}|4 }}|s |}|B |}|w |}|E |}|w |}|= }}| ~}|*}|=}|T}| m}| }}| 3}| [}| {}| <}| o}| 1}| n }| = }| x }|` }|C }|.~  }|&{  }|+{ }|5} }|P }| k }|Q }|| }| }| }|%o|$*|$Y|#w|"1|"V|5/- +)('&%$ $##""r V   ~I`D a h !X"":#x# $$$$$$$$$$$$$$$$$$$$$$$$$$$k2 .,,+*'&&%$#$$#""! ! !!    !!""#$$$$$$$$$$$$$$$$$$$$$$$$$$$56T161/-*)07-62, 7+62% 7)65'7(617'6/7&6.7%607$648$6!8#6. ;#6>"6,F"6P!62 X!6&l!6765<64 J60]6,76+>6*U6*76*B6*^6*;6* T6* 96*!Q6*!:6*"X6*">6*#p76*#L6*$6*%6*%6*%6*%6*%6*%6*%6*%6*%6*%6*%6*%6*%6*%6*%6*%6*%6*%6*%6*%6*%6*%6*%6*%6*%6*%6*%5-sT6"}-{O  }+|H })_}(}@}'{*}&{#}%},}$D |$d|#}v#Pm"}`"YR!)@!x* ]} Bs,Y~:}~}m}E}~}g}6} v}F}z} I} x}!>}!n}"&~}"Q}# }$}$}$}$}$}$}$}$}$}$}$}$}$}$}$}$}$}$}$}$}$}$}$}$}$}$}$>л 9a&.&   v Y   a  (=BY` !X"":#x# S8888888888888777546566! 3 1 0 1/ +'%  !!""#6.>6%76%6%76%6%76%6%76%6%76%6%76%6%76%6&76%6*76%6076%64 76%676%6"76%6-76%6576%6&76%6576%6)76%6576%6276%6- 76%6+ 76%6,v76%6Q16%6T5046%6T663156%6T63236%6T6533446%6T6%6T6%6T6%6T6%6T6%6U6%6W6&=6[76*v76P760Y6E864 H6@:6A6;=6">6B6/ <6D65)6=6H6/36=6Q6.66%@6G96036%F69?6-6% S76E63 j<6O6- G6@:6+ a< 6C6,N9 6M 6H9 6><6F:6E6H>76W86qE;6B6sE=;6P76`BJ8876 :6!X6!>6"p76"L6#=6 =|}||}||}||}||}||}||}||}|}}|~}|0}|K}|k}|~}|E}|u }|=}|w}|T}|2}|y}|t}|t-}||ы|||Ĩ| | ޕ | 豃 | ͌ |||Ў|oޣ}"}ć~=ޗ0VKdʌk mٞpphmw1 c}HTM ;}֟6 n⭆y N 縉t !l 뾏t:w Œ Dy ̚  @uԟ -\~ ڨ;g ⯇ +Kl뻊wő x!>!n"&~"Q# o j>=;972 0.-,*)'& j>=;9720.-,*)'&6 j>.=63$ ;6/":6/(7640--%2 65606.6-6,6*6)6'6&p- j>y0=Q ;v89s@7~fE(2 z>0 z_.h1-}[,8*l )'F&#$%&'())('&%$#"!  !# #$%&'())('&%$#"!  !# #6$6%6&6'6(6)6)6(6'6&6%6$6#6"6!66 6 6!6#6 -p!'x"-x#-p$'x%-x& `'!s&$k%"n$!s#$k""n!"s #n%p$u %p *p!%u#&p ++**)(('&%$#"!!#&  ,,,+*)))'&%$#"!!#& +64+6$*63*6!)6- (64(6"'6)&6. %60$61#6/"6-!6( 62 6+6/ 6/$"64-#$63/*& 6565420/$ +8+p*3*e)|(C(c't&{ %},$}1#|."w$!iKm"w;u@ !~_0#y\:& }wqjZG4 2 2 3 3 3 3 s2 n1 h0 W/;-,s+>){'&&S$`"I G#( A 2 2 3 3 3 3 3 3 2 1/.,,)'&$# #' A 26 26 36 36 36 36 Q36 T26 Y706 e9/6}>.6E-6W9+6uA*6S:(6H7&6lB7$6eB7"6mC9 6H>76 pB=86#D>;8640'P@;:97654312.  B 1 '1 V1 s1 2 /2 V2 91 4}0 &x/k.U,2y+_)3v( K}&U~$T}"Hw 0_~ 6\{#$B_x{d'&9IXcmvz}~{wneZK;* A  !"$%&()+ - . 136 "!! !#$%'(*,- 0 25 6%8 6- 861863864865865865 863!861"86,#865'$862&86+'862 )864(*8 65+,8 64*.8 62+0865/' 2864/+5866/(  m | z|~.|@|M|T|T|Q|G |}8!|v$#|e$|~E%|l '||D(|Z*| c!,| a%-| |T0|h; 2|~d>5|G)  $$$$$$$$$$$$$$$$$$$$ $$$$$$$$$$$$$$$$$$$$ 6*%6*%6*%6*%6*%6*%6*%6*%6*%6*%6*%6*%6*%6*%6*%6*%6*%6*%6*%6*%6* }$}$}$}$}$}$}$}$}$}$}$}$}$}$}$}$}$}$}$}$} $9%a&&'(&).*&+ -.v/Y 0 2a 45(7=9<B @$%%&'()*+,-/0 2 3 579< @$v76%Y6%H6&A6'>6(<6)=6*=6+@6,F6-S76/j< 60G 62a< 63N965H967F:69H>766<qE; @$"}%=%V&d' m(p)p*m+ c,T-;}/n 0N 2!l 3:w5 Dy7 @u9-\~<;g @%$"! !"""" !#%')*Y 0` %$"! !###" !#%')*0  6%6$6"6!6 6!6"6%"6%"6%"6 666!6#6%6'6)6*sE=;60`B=;:876 %/$^" ! @ }  / b  1 @ Z  q }! %# 4% >' P )^* +Klw0.AT؋#  76 5 4 3 2 10/.-+*)('%$#"  "#% 76 5 4 3 2 10/.-+*)('%$#"  "#% 7666 56 46 36 26 1606/6.6-6+6*6)6(6'6%6$6#6"6 66 6"6#6%6 Px4Px3 Px2 Px1 Hp0 @p/ @p.@p-8h,0`x* Px)Px(Hp'@p&8`x$ Px#Hp"8h!0`x Hp@p8`x  Hp"8h#(Xx%Hp   6    6    6  <;:875  <;:875  6<6;6:6867656  ?p=h8;x`0:pH 9p@7x`86pH 5h83xX(2pH  +,-./0 1 2 3 4 5789:;=? +,-./0 1 2 3 4 5789:;=? 6+6,6-6.6/60 61 62 63 64 656768696:6;6=6? xP+xP,xP- xP. pH/ p@0 p@1 p@2h83x`04xP 5xP7pH8p@9x`8:xP ;H=?????????????????&&&6&8`x???6????6????6?4 4 46 0x`8 ????????????????9999Po(7|9"isort your imports, so you don...!? "     %$#Sgimp-text-layer7(markup "isort your imports, so you don't have to.") (font "Sans-serif") (font-size 62.000000) (font-size-unit pixels) (antialias yes) (language "en-us") (base-direction ltr) (color (color-rgb 1.000000 1.000000 1.000000)) (justify center) (box-mode fixed) (box-width 892.000000) (box-height 57.000000) (box-unit pixels) (hinting yes) 5|95@|955={JKWcox4R@@@@#; ; ; <}* \( ]' S& nT! ! e! ! \ ! 1! sN! 7K! U'! J! !! T!  ! AlE! tM& v' 6";;;;* ('!!!! ! !!!! !!!! !!&'5"o;o;o;o;piP>8641**od>62)(o_760/07;?<76/'o85"nE5!oQ6&5^!o?6:!o<6S6!o@6%<6!oX66+# 75!oF630,!e63!oU?861-#]61!oF?<6/\61!o mEA764g64!oq>6075!o75=6!o85X6!o' 75t= =R<:::d;;;;;;                               >>==<999d65 ;75;75;75;75;75;75`=962. 86^=(86O65$6+ ,a@65,85sB76(86* N76634698664!85d96(76;6626* N66/"Q<66"85o86.+&75]6) C6585.<1756)A60 867/7582 86864 75# K6,86$ 75 m6586 75v 7685 75  8685 75Q 8685 75 7585 75/ b64 85 75& C6)85 754 j6685 756.;6-85 7576.k;6385 76UZ763+$bLD76485 862(2?C2^:6185 O65E:62)85 H86650)J:52&C+>>==<999d /0;:o;:o;:o;:o;:o;:o ly9NP!TgMPxPN OO:Tk(! ʳ kR  w _ kGw5:o5~)r:o % EL:oSWd 1| :o ) :os2 Tj :oV " :o>  :o*r@  :o[ , :oFL f_ :o  :of~ T :oB)1 :rQ>~ 7 nO C GEz/Tx ~:& ܈ -TaW5&0>3>==p<999^ ` lZa k  k ( k KY k    k Ol $ k   k  + k x4  k  R  k DO  k *  k  A y n   Z F { 82f H_d mbw  j] . p +<<<==>?                               <<<==>?ً , > |.  C{.  C9.  E8|.  I"4.   M .  ay .  h C.  t$ r.  oH .  o  ~.  ov* l6  or 3J  o l  olEc  o F ouhko ɨx>o CoD Q ژo{t<<=@==hOO ly9OP -PNNP!}:TE_ kʳ E_ kF<w _ E_ kGj)E_ l% EE_ qd 1E_ |  )E_  <:9 TjE_ bV "E_ jv> E_ ft@ E_ \[ ,Dc 18/ f_?o ( 0  h|~ T[B)1'niNQ>~^6 nO C 8f:A Txc.' e & Ph -TaW5 1Y_L <4<<c==> ?; ; ; <h  M  ix `  y   e~l'   J~      u   M|   ' j    ^    \    \    \    \    \    \    \    \    \    \    \ > > > > > > > > ;;;;                                 >>>>>>>>>o;o;o;o;p iۂp o ovǷ o5ݢ7Yіo@hQo(oY+o  o{ < oo  oo  oo  oo  oo  oo  oo  oo  oo  oo  oo  oo  >>>>>>>>> uxE;;;; mp@Tg NP.NP=?J2( WDWR Wz w5 Wrq]vZ /r(`EL-%v< q [f ( QW + PW , PW , PW , PW , PW , PW , PW , PW , PW , PW , PW ,>>>>>>>>>~<<<<<<` h a M `N K@Y %   Nl $       d +  4   R   O   &*   o A     [Z F ;2 _H_ Qmmb >j x . <<<<<<<}<<<<<<                                        <<<<<<<}<<<<<<ޖً >{ |C C Ϙ9EǷf8| "4Q tM a {   o h Ct o ;$ ro o X o o U ~o o 4* lo o r 3o   o ] uc o GFo slhko qȫPɨxo o o ow Qo odo<o<o<o<o<o<o<i} /0<:<:<:<:<:<:NO QD ly9NP!TgMPxLpY :Tk(L ʳ kR Y\w _ kGw5: ,j)r:)'% EL: fd 1| :   ) : >9 Tj : NgbV " : 7zv>  : :xt@  : Wb\[ , : :/ f_ :   :s v|~ T :D8*B)1 :]FNQ>~ 7/RDnO C - Tx  K & 2W`M-TaW5<<<<<<<NP.@>>>>>>>ddbbZZvv" " ! bb  zz 77UUO O!!!"  Ds Ds{U {U~~+ " <^<p!@>>>>>>>    ! !           !!        "<<!@M>J>J>J>J>J>J>99GGmmJ  JJ! J|!| J  J͟͟ JќќJ إإJ ݉݉JJ  Jb!bJo!oL S S+ +y y[ PՁՁy]]]"<=!@>o>o>o>o>o>o>PN 3oV3oV!@$@$cdTd^cdTd^o-%-%o[ [ o! o! o  oX X ou6u6o EX EX o PlPloYYo-@ -@o6!6o!r4 "x4 "xO1ԑ O1GEz/& &~a߽  a߽ ܈  fW fW&02K^\D 2K^\D"O8<<!`& `a  Za {   (Y Y 4 l $ Ol R + 4  qx4R  RO DO* ,* A FnZ FZ2c8H_Hmb mj j. .';t: :R:899                              ';:::788ً, |    {9 ] 98|  8"4 8I"M   M  yh C vh$ r  $  QH ~  * l/v*r 3r c lEcF Fhkuhɨx ɨx  QD 't;:;@:7h89 ly9OO OO l:T  }:ʳ  ʳw _ 5~ F<wj)  j)% E SWl%d 1 qd  ) s2 9 Tj <:9bV " bVv> *rjv>t@  ft@\[ ,FL\[/ f_18/ f(|~ T h|~B)1[BNQ>~ iNQnO C6 nOTx: T&e -TaW5-Ta'3;4::pc:78 8^>S=T=T=T=T=T=T=T lT kT k T k"h ks, k $ k u  k  q+ k  T k & T k C T k @ T k  TA y  T   qF { P 2f _dCDbwj3]i  p5v+>=======                                           >=======ً , ۆ|.  d.  w.  ڣ$r|.  54.  .  L .   C.  w r.  = .   ~.   l6  N 3J   l    ~  `k>δCQ ژm{Y>7x=w=w=w=w=w=w=wy9OP -PNP~=wTE_ y@w E_ ɳvw _ E_  ltwxE_ " EE_  ,#1E_  h &)E_  TjE_  4 w"E_  Xh w E_  kP wE_  hS w,Dc  Qs wf_?o  $ w0  ! T p )1'n e >~^Hv" C 8f:Alc93xc.' U& Ph =lW5 1Y_L 0N^H=1111111 ` 0a +  ^  X$ Y     l $        +  4  | R  z O  z *  z  A z   z Z F z 2 z H_ z mb z j z x. z =1111111                                                  =1111111 ً o| l 9)ċ 8|wN "4Y M m   h Cy  $ ro   o   ~o  * lo  r 3o   o  c o  Fo  hko  ɨxo   o  Qo  v=/1I /0/1P:/1P:/1P:/1P:/1P:/1P:/ ly9NPX.7MPx/:TW /ʳ WL /w _ WWD :/j)ir :/% EY9 :/d 1 :/  ) :/9 Tj  :/bV "  :/v>   :/t@   :/\[ ,  :// f_  :/   :/|~ T  :/B)1  :2NQ>~  7 nO C  !Tx  !&   -TaW5( ( ( ( ( ( ( ( U  5S Tc UPh B 2.  7  Z  f | zR zM z  zQ  z  z , zi z# z^ z zF+)((((((((                             (o(Mo(Jo(Jo(Jo(Jo(Jo(Jo( o= za onL oLRJqvPJj7MJLz JeJ =Jy  ULJo NJo NJo ̒NJo  NJo  NJo  NJo  NLo N o R o F8[ o bCP o ۩Cy(p uxE((o(o(o(o(o(o(PN gj Ep,OP*! ]%/  CT}^YxKo<4#& L'%oW \g+FoJRNo bIo?h|o  6ro KҧkTso 8so IR Bso  6so u$ 6so  6so  Rsr +s  :vGEz/  !v_)~  ȪDk܈  vq Ek&0(6XW=u;;;;;;r^ k   | bVJ Ou l ) t ߃: 4%AT RN OP&* m|9N Z WI;g  `n s \x +t;;;;;;                        tM;J;J;J;J;J;Jߞڑ  0 n W J [J9 GJ J(  JbI V JS{ J-  J} J 0JXpJLJ& N Jv' LD G B [ qP@yt /0;:o;:o;:o;:o;:o;:o/PKjDMPxPN  >m!0 @Pkx  ) }:o ~xD:oZk& Z^:o(  :o'7G  J: :o ?p z :o9ufv ,@ ,[ ,, f_, ,~ T,B)1-NQ>~cԯ&nO Cw'Txw(&w*-TaW5 \ \ \ \o7z0 Layer #5!? "     %$#z08DP\z0^n~(8HXhx(8HXhx(8HXhx(8HXhx(''''''''''''''''''''''''3 3 3 3 3                                                        Lo&7\i!? "     9%$#gimp-text-layer(markup "i") (font "Sans-serif") (font-size 62.000000) (font-size-unit pixels) (antialias yes) (language "en-us") (base-direction ltr) (color (color-rgb 0.937255 0.513725 0.211765)) (justify center) (box-mode fixed) (box-width 275.000000) (box-height 348.000000) (box-unit pixels) (hinting yes) '\[BNZ\[k{ӂւֲ֢֒"2 D0+({$)"Y hma C! /*'$"  "# u/ъ+^'%#!j+!# L̥j#/T W*o<'W$"? ]l6aEA"#Z$%r%&\&''S''(('''&&$;##!" {  :"Q$A'+P /&^^^^$&&''(()))***)))((&%%$"! "$'+/ &            "~$$%M%r&'''t'Q(( ('V'&& %$#Q"!( #{%1'a+ Z/э'k-j-j-j-j!!" o"?$q%%%&5&x'w&J& &%y#%#% $8$# c!a  4  5 "B_$/' 2+# ߈%/ Jʤn/&N[+N[+N[,N[,N ^^^^^^^^\\\\\                                         -j-j-j-j-j-j-j-j-j-j-j-j- [,N[,N[,N[,M[,M[,M[,M[,M[,M[,M[,M[,M[,?>>\>>===\==<<<\<<;;;\;;:::\::999\99>>>>=====<<<<<;;;;;:::::9999988>>>>=====<<<<<;;;;;:::::9999988>>>M>====M=<<<<M<;;;;M;::::M:9999M988\     !!!!!"""""#####$$$$$%%%     !!!!!"""""#####$$$$$%%%j-  j -  !!j!-!!""l"-""##l#-##$$l$-$$%%l%-%%M[, [ ,   ![!,!!!"[","""#[#,###$[$,$$$%[%,%DW"+\i #3!<9X "      %$#gimp-text-layer(markup "i") (font "Sans-serif") (font-size 62.000000) (font-size-unit pixels) (antialias yes) (language "en-us") (base-direction ltr) (color (color-rgb 0.937255 0.513725 0.211765)) (justify center) (box-mode fixed) (box-width 275.000000) (box-height 348.000000) (box-unit pixels) (hinting yes) (\\CO[\\l|#3 D0+({$)"Y hma C! /*'$"  "# u/ъ+^'%#!j+!# L̥j#/T W*o<'W$"? ]l6aEA"#Z$%r%&\&''S''(('''&&$;##!" {  :"Q$A'+P /&^^^^$&&''(()))***)))((&%%$"! "$'+/ &            "~$$%M%r&'''t'Q(( ('V'&& %$#Q"!( #{%1'a+ Z/э'k-j-j-j-j!!" o"?$q%%%&5&x'w&J& &%y#%#% $8$# c!a  4  5 "B_$/' 2+# ߈%/ Jʤn/&N[+N[+N[,N[,N ^^^^^^^^\\\\\                                         -j-j-j-j-j-j-j-j-j-j-j-j- [,N[,N[,N[,M[,M[,M[,M[,M[,M[,M[,M[,M[,?>>\>>===\==<<<\<<;;;\;;:::\::999\99>>>>=====<<<<<;;;;;:::::9999988>>>>=====<<<<<;;;;;:::::9999988>>>M>====M=<<<<M<;;;;M;::::M:9999M988\     !!!!!"""""#####$$$$$%%%     !!!!!"""""#####$$$$$%%%j-  j -  !!j!-!!""l"-""##l#-##$$l$-$$%%l%-%%M[, [ ,   ![!,!!!"[","""#[#,###$[$,$$$%[%,%DW"+\i #2!=x "     (%$#gimp-text-layer(markup "i") (font "Sans-serif") (font-size 62.000000) (font-size-unit pixels) (antialias yes) (language "en-us") (base-direction ltr) (color (color-rgb 0.937255 0.513725 0.211765)) (justify center) (box-mode fixed) (box-width 275.000000) (box-height 348.000000) (box-unit pixels) (hinting yes) )\] D P \\]m}   $ 4 D0+({$)"Y hma C! /*'$"  "# u/ъ+^'%#!j+!# L̥j#/T W*o<'W$"? ]l6aEA"#Z$%r%&\&''S''(('''&&$;##!" {  :"Q$A'+P /&^^^^$&&''(()))***)))((&%%$"! "$'+/ &            "~$$%M%r&'''t'Q(( ('V'&& %$#Q"!( #{%1'a+ Z/э'k-j-j-j-j!!" o"?$q%%%&5&x'w&J& &%y#%#% $8$# c!a  4  5 "B_$/' 2+# ߈%/ Jʤn/&N[+N[+N[,N[,N ^^^^^^^^\\\\\                                         -j-j-j-j-j-j-j-j-j-j-j-j- [,N[,N[,N[,M[,M[,M[,M[,M[,M[,M[,M[,M[,?>>\>>===\==<<<\<<;;;\;;:::\::999\99>>>>=====<<<<<;;;;;:::::9999988>>>>=====<<<<<;;;;;:::::9999988>>>M>====M=<<<<M<;;;;M;::::M:9999M988\     !!!!!"""""#####$$$$$%%%     !!!!!"""""#####$$$$$%%%j-  j -  !!j!-!!""l"-""##l#-##$$l$-$$%%l%-%%M[, [ ,   ![!,!!!"[","""#[#,###$[$,$$$%[%,%DW"+\i #1_!> "     1%$#gimp-text-layer(markup "i") (font "Sans-serif") (font-size 62.000000) (font-size-unit pixels) (antialias yes) (language "en-us") (base-direction ltr) (color (color-rgb 0.937255 0.513725 0.211765)) (justify center) (box-mode fixed) (box-width 275.000000) (box-height 348.000000) (box-unit pixels) (hinting yes)  *\ ^"E"Q"]\ ^ n ~!!!!!!!!"""%"5 D0+({$)"Y hma C! /*'$"  "# u/ъ+^'%#!j+!# L̥j#/T W*o<'W$"? ]l6aEA"#Z$%r%&\&''S''(('''&&$;##!" {  :"Q$A'+P /&^^^^$&&''(()))***)))((&%%$"! "$'+/ &            "~$$%M%r&'''t'Q(( ('V'&& %$#Q"!( #{%1'a+ Z/э'k-j-j-j-j!!" o"?$q%%%&5&x'w&J& &%y#%#% $8$# c!a  4  5 "B_$/' 2+# ߈%/ Jʤn/&N[+N[+N[,N[,N ^^^^^^^^\\\\\                                         -j-j-j-j-j-j-j-j-j-j-j-j- [,N[,N[,N[,M[,M[,M[,M[,M[,M[,M[,M[,M[,?>>\>>===\==<<<\<<;;;\;;:::\::999\99>>>>=====<<<<<;;;;;:::::9999988>>>>=====<<<<<;;;;;:::::9999988>>>M>====M=<<<<M<;;;;M;::::M:9999M988\     !!!!!"""""#####$$$$$%%%     !!!!!"""""#####$$$$$%%%j-  j -  !!j!-!!""l"-""##l#-##$$l$-$$%%l%-%%M[, [ ,   ![!,!!!"[","""#[#,###$[$,$$$%[%,%DW"+}i #4!? "     %$#1gimp-text-layer(markup "i") (font "Sans-serif") (font-size 62.000000) (font-size-unit pixels) (antialias yes) (language "en-us") (base-direction ltr) (color (color-rgb 0.000000 0.000000 0.000000)) (justify left) (box-mode fixed) (box-width 125.000000) (box-height 235.000000) (box-unit pixels) (hinting yes) %"}%N6V6b}%':'J--'336F N0 ,t(%E#L!@G "F"# /,(%#! ""$$& ܹ+T G/^W! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! !@@@@                                                                                                                                 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! !@@@@                                           !!!!!!!!!!!!!!!!!!!! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ? ? ? ?>u:z0 Layer #7!? "     %$#C7oz07F7FCFOF[z099: ::+:;:K:[:k:{::::::::; ;;+;;;K;[;k;{;;;;;;;;< <<+<;+>?_?@A-ABaBCE7EGEWEgEwEEEEEEEEFFF'0P_rƾ/0P-@ , p*@)`(`'`&`&@% $p$@##0#P""0"P"_"o"""""o"_"P"0"#P#0#$@$p% &@&`'`(`)`*@, p-@ /0P20P`sƿûûûûûþûþû »»»»ü¿üÿüÿüþûþûþŻþùþùþùþù ÿüÿüÿƼÿĺÿĺÿĺÿĺþùþùþùþùþùþüþ ÿĺÿĺÿĺÿĺÿĺÿļÿ»þþþƾûûû ӿ»ÿ»ÿ»ÿ»ƿ»»»üûûþûþûþûþûþŻ »ü¿üÿüÿüÿüÿüÿƼþùþùþùþùþùþùþù ÿĺÿĺÿĺÿĺÿĺÿĺÿĺþùþùþüþþþþ ÿĺÿĺÿļÿ»ÿ»ÿ»ÿ»ƾûûûûûþû »ƿ»»»»ü¿üÿüþûþûþûþŻþùþùþù ÿüÿüÿüÿƼÿĺÿĺÿĺþùþo_P0)կP0&ϯ@$p #ߏ@!` ```@  p!@!"0"P"#0#P#_#o$$$$#o#_#P#0""P"0!!@ p @```` ߏ@!p #ϯ@$կP0&ÿĺÿp`P0                                                        Lo&7z< Layer #3 != "     %$#Ghz<Gwpw|wwz<IIJLO8OHOXOhOxOOOOOOOOV^^^^^_ __)_9_I_Y_i_yiFnnnnnnnooo/o?oOo_sfuvvv v0v@vPv`vpvvvvvvvvwww w0w@wPw` K/6 -] +H*(:'d&o%o$k#M")"!l $ 'T  /-+)('&%$#"!!    !! /-+)('&%$#"!!    !! &CXit{~yrcO6/ 4`~ -Mz+P~);z(e'(w&5}%<$7~#(}"w!f!D |\!~Y|=c { >;976 5 4 3 3 K 6 ]    "#%'() >;976 5 4 3 3    ()*+,,-... |>۵J;19v87 544 c3 | ۵J 1 v      c    s >n= ;{G 9v.7Q6a 5b4 Y3 =3 z &CXit{~yrcO6 W 4`~ n=  }Mz{G  \P~v. Q a bY=zW}LRt    |`%K e  J!z"#$%t&()F.x   < u !!!'%'}'n'W(>(%(}(n(W)>)%)})n)W*>*%*}*n*W+>+%+  8 s   8 s   8 s   8 q  '8's''&&8&q&&6666777778888899999::''&&&&&%%%%%%%%%%%%%%%%%%%%%%%''&&&&&%%y ~ 2 L d y ~ 2 L d y ~ 2 L d y ~ 2 L d y '2'L&d&y&~&2&L%d%y++,,,,,-----...../////00000 1 1 ++,,,,,-----...../////00000 1 1 +,,W,,,--W---..Y.../ / Y/ / / 0 0 Y0 0 0 1 1 X1 }+n+W,>,%,},n,W->-%-}-n-W.>.%.}.n.W/>/ %/ }/ n/ W0 >0 %0 }0 o0 W1 >1 %    Oo'7z0 Layer #4!? "     %$#xz0x}z0{{-{={M{]{m{}{{{{{{{{| ||-|=|M|]|m|}||||||||} }}-}=}M}]}m}}}}}}}}}}~ ~~-~=~M~]~m~}~~~~~~~~ -=M]m                                                        Lo&7z0 Layer #6!? ~ "     %$#z0jvz0*:JZjz *:JZjz *:JZjz *Jj *Jj *:JZtttttttttttttttttttttttttttttttttttttttttt t    t    t    t    t    t    t    t    t    t    t    t    t    t                                                           Lo&7z0 Background!? "     %$#z0iuz0!-9EQ]iu)5AMYeq} %1=IUamy !-9EQ]tttttttttttttttttttttttttttttttttttttttttttttttttttttttt  t   t   t   t   t   t   t   t   t   t   t   t   t   t Lo&7isort-6.0.1/art/stylesheets/extra.css0000644000000000000000000000023613615410400014576 0ustar00[data-md-color-scheme="isort"] { --md-primary-fg-color: #EF8336; --md-primary-fg-color--light: #1674B1; --md-primary-fg-color--dark: #1674b1; } isort-6.0.1/docs/configuration/action_comments.md0000644000000000000000000000477013615410400017111 0ustar00# Action Comments The most basic way to configure the flow of isort within a single file is action comments. These comments are picked up and interpreted by the isort parser during parsing. ## isort: skip_file Tells isort to skip the entire file. Example: ```python # !/bin/python3 # isort: skip_file import os import sys ... ``` !!! warning This should be placed as high in the file as reasonably possible. Since isort uses a streaming architecture, it may have already completed some work before it reaches the comment. Usually, this is okay - but can be confusing if --diff or any interactive options are used from the command line. ## isort: skip If placed on the same line as (or within the continuation of a) an import statement, isort will not sort this import. More specifically, it prevents the import statement from being recognized by isort as an import. In consequence, this line will be treated as code and be pushed down to below the import section of the file. Example: ```python import b import a # isort: skip <- this will now stay below b ``` !!! note It is recommended to where possible use `# isort: off` and `# isort: on` or `# isort: split` instead as the behavior is more explicit and predictable. ## isort: off Turns isort parsing off. Every line after an `# isort: off` statement will be passed along unchanged until an `# isort: on` comment or the end of the file. Example: ```python import e import f # isort: off import b import a ``` ## isort: on Turns isort parsing back on. This only makes sense if an `# isort: off` comment exists higher in the file! This allows you to have blocks of unsorted imports, around otherwise sorted ones. Example: ```python import e import f # isort: off import b import a # isort: on import c import d ``` ## isort: split Tells isort the current sort section is finished, and all future imports belong to a new sort grouping. Example: ```python import e import f # isort: split import a import b import c import d ``` You can also use it inline to keep an import from having imports above or below it swap position: ```python import c import b # isort: split import a ``` !!! tip isort split is exactly the same as placing an `# isort: on` immediately below an `# isort: off` ## isort: dont-add-imports Tells isort to not automatically add imports to this file, even if --add-imports is set. ## isort: dont-add-import: [IMPORT_LINE] Tells isort to not automatically add a particular import, even if --add-imports says to add it. isort-6.0.1/docs/configuration/add_or_remove_imports.md0000644000000000000000000000117413615410400020304 0ustar00 ## Adding an import to multiple files isort makes it easy to add an import statement across multiple files, while being assured it's correctly placed. To add an import to all files: ```bash isort -a "from __future__ import print_function" *.py ``` To add an import only to files that already have imports: ```bash isort -a "from __future__ import print_function" --append-only *.py ``` ## Removing an import from multiple files isort also makes it easy to remove an import from multiple files, without having to be concerned with how it was originally formatted. From the command line: ```bash isort --rm "os.system" *.py ``` isort-6.0.1/docs/configuration/black_compatibility.md0000644000000000000000000000413513615410400017727 0ustar00![isort loves black](https://raw.githubusercontent.com/pycqa/isort/main/art/isort_loves_black.png) # Compatibility with black Compatibility with black is very important to the isort project and comes baked in starting with version 5. All that's required to use isort alongside black is to set the isort profile to "black". !!! tip Beyond the profile, it is common to set [skip_gitignore](https://pycqa.github.io/isort/docs/configuration/options.html#skip-gitignore) (which is not enabled by default for isort as it requires git to be installed) and [line_length](https://pycqa.github.io/isort/docs/configuration/options.html#line-length) as it is common to deviate from black's default of 88. ## Using a config file (such as .isort.cfg) For projects that officially use both isort and black, we recommend setting the black profile in a config file at the root of your project's repository. That way it's independent of how users call isort (pre-commit, CLI, or editor integration) the black profile will automatically be applied. For instance, your _pyproject.toml_ file would look something like ```ini [tool.isort] profile = "black" ``` Read More about supported [config files](https://pycqa.github.io/isort/docs/configuration/config_files.html). ## CLI To use the profile option when calling isort directly from the commandline simply add the --profile black argument: `isort --profile black`. A demo of how this would look like in your _.travis.yml_ ```yaml language: python python: - "3.10" - "3.9" install: - pip install -r requirements-dev.txt - pip install isort black - pip install coveralls script: - pytest my-package - isort --profile black my-package - black --check --diff my-package after_success: - coveralls ``` See [built-in profiles](https://pycqa.github.io/isort/docs/configuration/profiles.html) for more profiles. ## Integration with pre-commit You can also set the profile directly when integrating isort within pre-commit. ```yaml - repo: https://github.com/pycqa/isort rev: 5.13.2 hooks: - id: isort args: ["--profile", "black", "--filter-files"] ``` isort-6.0.1/docs/configuration/config_files.md0000644000000000000000000001242213615410400016347 0ustar00Supported Config Files ======== isort supports various standard config formats to allow customizations to be integrated into any project quickly. When applying configurations, isort looks for the closest supported config file, in the order files are listed below. You can manually specify the settings file or path by setting `--settings-path` from the command-line. Otherwise, isort will traverse up to 25 parent directories until it finds a suitable config file. Note that isort will not leave a git or Mercurial repository (checking for a `.git` or `.hg` directory). As soon as it finds a file, it stops looking. The config file search is done relative to the current directory if `isort .` or a file stream is passed in, or relative to the first path passed in if multiple paths are passed in. isort **never** merges config files together due to the confusion it can cause. !!! tip You can always introspect the configuration settings isort determined, and find out which config file it picked up, by running `isort . --show-config` ## .isort.cfg **[preferred format]** The first place isort will look for settings is in dedicated .isort.cfg files. The advantage of using this kind of config file, is that it is explicitly for isort and follows a well understood format. The downside, is that it means one more config file in your project when you may already have several polluting your file hierarchy. An example a config from the isort project itself: ```ini [settings] profile=hug src_paths=isort,test ``` ## pyproject.toml **[preferred format]** The second place isort will look, and an equally excellent choice to place your configuration, is within a pyproject.toml file. The advantage of using this config file, is that it is quickly becoming a standard place to configure all Python tools. This means other developers will know to look here and you will keep your projects root nice and tidy. The only disadvantage is that other tools you use might not yet support this format, negating the cleanliness. ```toml [tool.isort] profile = "hug" src_paths = ["isort", "test"] ``` ## setup.cfg `setup.cfg` can be thought of as the precursor to `pyproject.toml`. While isort and newer tools are increasingly moving to pyproject.toml, if you rely on many tools that use this standard it can be a natural fit to put your isort config there as well. ```ini [isort] profile=hug src_paths=isort,test ``` ## tox.ini [tox](https://tox.readthedocs.io/en/latest/) is a tool commonly used in the Python community to specify multiple testing environments. Because isort verification is commonly ran as a testing step, some prefer to place the isort config inside of the tox.ini file. ```ini [isort] profile = black multi_line_output = 3 ``` ## .editorconfig Finally, isort will look for a `.editorconfig` configuration with settings for Python source files. [EditorConfig](https://editorconfig.org/) is a project to enable specifying a configuration for text editing behaviour once, allowing multiple command line tools and text editors to pick it up. Since isort cares about a lot of the same settings as a text-editor (like line-length) it makes sense for it to look within these files as well. ``` root = true [*.py] profile = hug indent_style = space indent_size = 4 skip = build,.tox,venv src_paths=isort,test ``` ## Custom config files Optionally, you can also create a config file with a custom name, or directly point isort to a config file that falls lower in the priority order, by using [--settings-file](https://pycqa.github.io/isort/docs/configuration/options.html#settings-path). This can be useful, for instance, if you want to have one configuration for `.py` files and another for `.pyx` - while keeping the config files at the root of your repository. !!! tip Custom config files should place their configuration options inside an `[isort]` section and never a generic `[settings]` section. This is because isort can't know for sure how other tools are utilizing the config file. ## Supporting multiple config files in single isort run If you have a directory structure where different sub-directories may have their separate configuration settings and you want isort to respect these configurations, not just apply the same global configuration for the entire directory then you can do so with the `--resolve-all-configs` flag. Using the `--resolve-all-configs` along with providing the directory root as `--config-root` argument(if the config-root is not explicitly defined, then isort will consider the current directory `.` where the shell is running), isort will traverse and parse all the config files defined under the `--config-root` and dynamically decide what configurations should be applied to a specific file by choosing the nearest config file in the file's path. For instance, if your directory structure is ``` directory_root subdir1 .isort.cfg file1.py subdir2 pyproject.toml file2.py subdir3 file3.py setup.cfg ``` isort will sort `subdir1/file1` according to the configurations defined in `subdir1/.isort.cfg`, `subdir2/file2` with configurations from `subdir2/pyproject.toml` and `subdir3/file3.py` based on the `setup.cfg` settings. !!! tip You can always confirm exactly what config file was used for a file by running isort with the `--verbose` flag. isort-6.0.1/docs/configuration/custom_sections_and_ordering.md0000644000000000000000000000721413615410400021657 0ustar00# Custom Sections and Ordering isort provides lots of features to enable configuring how it sections imports and how it sorts imports within those sections. You can change the section order with `sections` option from the default of: ```ini FUTURE,STDLIB,THIRDPARTY,FIRSTPARTY,LOCALFOLDER ``` to your preference (if defined, omitting a default section may cause errors): ```ini sections=FUTURE,STDLIB,FIRSTPARTY,THIRDPARTY,LOCALFOLDER ``` You also can define your own sections and their order. Example: ```ini known_django=django known_pandas=pandas,numpy sections=FUTURE,STDLIB,DJANGO,THIRDPARTY,PANDAS,FIRSTPARTY,LOCALFOLDER ``` would create two new sections with the specified known modules. The `no_lines_before` option will prevent the listed sections from being split from the previous section by an empty line. Example: ```ini sections=FUTURE,STDLIB,THIRDPARTY,FIRSTPARTY,LOCALFOLDER no_lines_before=LOCALFOLDER ``` would produce a section with both FIRSTPARTY and LOCALFOLDER modules combined. **IMPORTANT NOTE**: It is very important to know when setting `known` sections that the naming does not directly map for historical reasons. For custom settings, the only difference is capitalization (`known_custom=custom` VS `sections=CUSTOM,...`) for all others reference the following mapping: - `known_standard_library` : `STANDARD_LIBRARY` - `extra_standard_library` : `STANDARD_LIBRARY` # Like known standard library but appends instead of replacing - `known_future_library` : `FUTURE` - `known_first_party`: `FIRSTPARTY` - `known_third_party`: `THIRDPARTY` - `known_local_folder`: `LOCALFOLDER` This will likely be changed in isort 6.0.0+ in a backwards compatible way. ## Auto-comment import sections Some projects prefer to have import sections uniquely titled to aid in identifying the sections quickly when visually scanning. isort can automate this as well. To do this simply set the `import_heading_{section_name}` setting for each section you wish to have auto commented - to the desired comment. For Example: ```ini import_heading_stdlib=Standard Library import_heading_firstparty=My Stuff ``` Would lead to output looking like the following: ```python # Standard Library import os import sys import django.settings # My Stuff import myproject.test ``` ## Ordering by import length isort also makes it easy to sort your imports by length, simply by setting the `length_sort` option to `True`. This will result in the following output style: ```python from evn.util import ( Pool, Dict, Options, Constant, DecayDict, UnexpectedCodePath, ) ``` It is also possible to opt-in to sorting imports by length for only specific sections by using `length_sort_` followed by the section name as a configuration item, e.g.: length_sort_stdlib=1 ## Controlling how isort sections `from` imports By default isort places straight (`import y`) imports above from imports (`from x import y`): ```python import b from a import a # This will always appear below because it is a from import. ``` However, if you prefer to keep strict alphabetical sorting you can set [force sort within sections](https://pycqa.github.io/isort/docs/configuration/options.html#force-sort-within-sections) to true. Resulting in: ```python from a import a # This will now appear at top because a appears in the alphabet before b import b ``` You can even tell isort to always place from imports on top, instead of the default of placing them on bottom, using [from first](https://pycqa.github.io/isort/docs/configuration/options.html#from-first). ```python from b import b # If from first is set to True, all from imports will be placed before non-from imports. import a ``` isort-6.0.1/docs/configuration/git_hook.md0000644000000000000000000000276013615410400015527 0ustar00# Git Hook isort provides a hook function that can be integrated into your Git pre-commit script to check Python code before committing. To cause the commit to fail if there are isort errors (strict mode), include the following in `.git/hooks/pre-commit`: ```python #!/usr/bin/env python import sys from isort.hooks import git_hook sys.exit(git_hook(strict=True, modify=True, lazy=True, settings_file="")) ``` If you just want to display warnings, but allow the commit to happen anyway, call `git_hook` without the strict parameter. If you want to display warnings, but not also fix the code, call `git_hook` without the modify parameter. The `lazy` argument is to support users who are "lazy" to add files individually to the index and tend to use `git commit -a` instead. Set it to `True` to ensure all tracked files are properly isorted, leave it out or set it to `False` to check only files added to your index. If you want to use a specific configuration file for the hook, you can pass its path to settings_file. If no path is specifically requested, `git_hook` will search for the configuration file starting at the directory containing the first staged file, as per `git diff-index` ordering, and going upward in the directory structure until a valid configuration file is found or [`MAX_CONFIG_SEARCH_DEPTH`](src/config.py:35) directories are checked. The settings_file parameter is used to support users who keep their configuration file in a directory that might not be a parent of all the other files. isort-6.0.1/docs/configuration/github_action.md0000644000000000000000000000374413615410400016546 0ustar00# Github Action isort provides an official [Github Action][github-action-docs] that can be used as part of a CI/CD workflow to ensure a project's imports are properly sorted. The action can be found on the [Github Actions Marketplace][python-isort]. ## Usage The `python-isort` plugin is designed to be run in combination with the [`checkout`][checkout-action] and [`setup-python`][setup-python] actions. By default, it will run recursively from the root of the repository being linted and will exit with an error if the code is not properly sorted. ### Inputs #### `isort-version` Optional. Version of `isort` to use. Defaults to latest version of `isort`. #### `sort-paths` Optional. List of paths to sort, relative to your project root. Defaults to `.` #### `configuration` Optional. `isort` configuration options to pass to the `isort` CLI. Defaults to `--check-only --diff`. #### `requirements-files` Optional. Paths to python requirements files to install before running isort. If multiple requirements files are provided, they should be separated by a space. If custom package installation is required, dependencies should be installed in a separate step before using this action. !!! tip It is important that the project's dependencies be installed before running isort so that third-party libraries are properly sorted. ### Outputs #### `isort-result` Output of the `isort` CLI. ### Example usage ```yaml name: Run isort on: - push jobs: build: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - uses: actions/setup-python@v5 with: python-version: 3.13 - uses: isort/isort-action@v1 with: requirementsFiles: "requirements.txt requirements-test.txt" ``` [github-action-docs]: https://docs.github.com/en/free-pro-team@latest/actions [python-isort]: https://github.com/marketplace/actions/python-isort [checkout-action]: https://github.com/actions/checkout [setup-python]: https://github.com/actions/setup-python isort-6.0.1/docs/configuration/multi_line_output_modes.md0000644000000000000000000000437013615410400020673 0ustar00# Multi Line Output Modes This [config option](https://pycqa.github.io/isort/docs/configuration/options.html#multi-line-output) defines how from imports wrap when they extend past the line\_length limit and has 12 possible settings: ## 0 - Grid ```python from third_party import (lib1, lib2, lib3, lib4, lib5, ...) ``` ## 1 - Vertical ```python from third_party import (lib1, lib2, lib3 lib4, lib5, ...) ``` ## 2 - Hanging Indent ```python from third_party import \ lib1, lib2, lib3, \ lib4, lib5, lib6 ``` ## 3 - Vertical Hanging Indent ```python from third_party import ( lib1, lib2, lib3, lib4 ) ``` ## 4 - Hanging Grid ```python from third_party import ( lib1, lib2, lib3, lib4, lib5, ...) ``` ## 5 - Hanging Grid Grouped ```python from third_party import ( lib1, lib2, lib3, lib4, lib5, ... ) ``` ## 6 - Hanging Grid Grouped Same as Mode 5. Deprecated. ## 7 - NOQA ```python from third_party import lib1, lib2, lib3, ... # NOQA ``` Alternatively, you can set `force_single_line` to `True` (`-sl` on the command line) and every import will appear on its own line: ```python from third_party import lib1 from third_party import lib2 from third_party import lib3 ... ``` ## 8 - Vertical Hanging Indent Bracket Same as Mode 3 - _Vertical Hanging Indent_ but the closing parentheses on the last line is indented. ```python from third_party import ( lib1, lib2, lib3, lib4, ) ``` ## 9 - Vertical Prefix From Module Import Starts a new line with the same `from MODULE import` prefix when lines are longer than the line length limit. ```python from third_party import lib1, lib2, lib3 from third_party import lib4, lib5, lib6 ``` ## 10 - Hanging Indent With Parentheses Same as Mode 2 - _Hanging Indent_ but uses parentheses instead of backslash for wrapping long lines. ```python from third_party import ( lib1, lib2, lib3, lib4, lib5, lib6) ``` ## 11 - Backslash Grid Same as Mode 0 - _Grid_ but uses backslashes instead of parentheses to group imports. ```python from third_party import lib1, lib2, lib3, \ lib4, lib5 ``` isort-6.0.1/docs/configuration/options.md0000644000000000000000000013115313615410400015416 0ustar00# Configuration options for isort As a code formatter isort has opinions. However, it also allows you to have your own. If your opinions disagree with those of isort, isort will disagree but commit to your way of formatting. To enable this, isort exposes a plethora of options to specify how you want your imports sorted, organized, and formatted. Too busy to build your perfect isort configuration? For curated common configurations, see isort's [built-in profiles](https://pycqa.github.io/isort/docs/configuration/profiles.html). ## Python Version Tells isort to set the known standard library based on the specified Python version. Default is to assume any Python 3 version could be the target, and use a union of all stdlib modules across versions. If auto is specified, the version of the interpreter used to run isort (currently: 39) will be used. **Type:** String **Default:** `py3` **Config default:** `3` **Python & Config File Name:** py_version **CLI Flags:** - --py - --python-version **Examples:** ### Example `.isort.cfg` ``` [settings] py_version=39 ``` ### Example `pyproject.toml` ``` [tool.isort] py_version=39 ``` ### Example cli usage `isort --py 39` ## Force To Top Force specific imports to the top of their appropriate section. **Type:** List of Strings **Default:** `frozenset()` **Config default:** `[]` **Python & Config File Name:** force_to_top **CLI Flags:** - -t - --top ## Skip Files that isort should skip over. If you want to skip multiple files you should specify twice: `--skip file1 --skip file2`. Values can be file names, directory names or file paths. To skip all files in a nested path, use [`--skip-glob`](#skip-glob). To even skip matching files that have been specified on the command line, use [`--filter-files`](#filter-files). **Type:** List of Strings **Default:** `('.bzr', '.direnv', '.eggs', '.git', '.hg', '.mypy_cache', '.nox', '.pants.d', '.pytype' '.svn', '.tox', '.venv', '__pypackages__', '_build', 'buck-out', 'build', 'dist', 'node_modules', 'venv')` **Config default:** `['.bzr', '.direnv', '.eggs', '.git', '.hg', '.mypy_cache', '.nox', '.pants.d', '.svn', '.tox', '.venv', '__pypackages__', '_build', 'buck-out', 'build', 'dist', 'node_modules', 'venv']` **Python & Config File Name:** skip **CLI Flags:** - -s - --skip **Examples:** ### Example `.isort.cfg` ``` [settings] skip=.gitignore,.dockerignore ``` ### Example `pyproject.toml` ``` [tool.isort] skip = [".gitignore", ".dockerignore"] ``` ## Extend Skip Extends --skip to add additional files that isort should skip over. If you want to skip multiple files you should specify twice: --skip file1 --skip file2. Values can be file names, directory names or file paths. To skip all files in a nested path, use [`--skip-glob`](#skip-glob). To even skip matching files that have been specified on the command line, use [`--filter-files`](#filter-files). **Type:** List of Strings **Default:** `frozenset()` **Config default:** `[]` **Python & Config File Name:** extend_skip **CLI Flags:** - --extend-skip **Examples:** ### Example `.isort.cfg` ``` [settings] extend_skip=.md,.json ``` ### Example `pyproject.toml` ``` [tool.isort] extend_skip = [".md", ".json"] ``` ## Skip Glob Files that isort should skip over. To even skip matching files that have been specified on the command line, use [`--filter-files`](#filter-files). **Type:** List of Strings **Default:** `frozenset()` **Config default:** `[]` **Python & Config File Name:** skip_glob **CLI Flags:** - --sg - --skip-glob **Examples:** ### Example `.isort.cfg` ``` [settings] skip_glob=docs/* ``` ### Example `pyproject.toml` ``` [tool.isort] skip_glob = ["docs/*"] ``` ## Extend Skip Glob Additional files that isort should skip over (extending --skip-glob). To even skip matching files that have been specified on the command line, use [`--filter-files`](#filter-files). **Type:** List of Strings **Default:** `frozenset()` **Config default:** `[]` **Python & Config File Name:** extend_skip_glob **CLI Flags:** - --extend-skip-glob **Examples:** ### Example `.isort.cfg` ``` [settings] extend_skip_glob=my_*_module.py,test/* ``` ### Example `pyproject.toml` ``` [tool.isort] extend_skip_glob = ["my_*_module.py", "test/*"] ``` ## Skip Gitignore Treat project as a git repository and ignore files listed in .gitignore. To even skip matching files that have been specified on the command line, use [`--filter-files`](#filter-files). NOTE: This requires git to be installed and accessible from the same shell as isort. **Type:** Bool **Default:** `False` **Config default:** `false` **Python & Config File Name:** skip_gitignore **CLI Flags:** - --gitignore - --skip-gitignore ## Line Length The max length of an import line (used for wrapping long imports). **Type:** Int **Default:** `79` **Config default:** `79` **Python & Config File Name:** line_length **CLI Flags:** - -l - -w - --line-length - --line-width ## Wrap Length Specifies how long lines that are wrapped should be, if not set line_length is used. NOTE: wrap_length must be LOWER than or equal to line_length. **Type:** Int **Default:** `0` **Config default:** `0` **Python & Config File Name:** wrap_length **CLI Flags:** - --wl - --wrap-length ## Line Ending Forces line endings to the specified value. If not set, values will be guessed per-file. **Type:** String **Default:** ` ` **Config default:** ` ` **Python & Config File Name:** line_ending **CLI Flags:** - --le - --line-ending ## Sort Re-exports Specifies whether to sort re-exports (`__all__` collections) automatically. **Type:** Bool **Default:** `False` **Config default:** `false` **Python & Config File Name:** sort_reexports **CLI Flags:** - --srx - --sort-reexports ## Sections What sections isort should display imports for and in what order **Type:** List of Strings **Default:** `('FUTURE', 'STDLIB', 'THIRDPARTY', 'FIRSTPARTY', 'LOCALFOLDER')` **Config default:** `['FUTURE', 'STDLIB', 'THIRDPARTY', 'FIRSTPARTY', 'LOCALFOLDER']` **Python & Config File Name:** sections **CLI Flags:** **Not Supported** ## No Sections Put all imports into the same section bucket **Type:** Bool **Default:** `False` **Config default:** `false` **Python & Config File Name:** no_sections **CLI Flags:** - --ds - --no-sections ## Known Future Library Force isort to recognize a module as part of Python's internal future compatibility libraries. WARNING: this overrides the behavior of __future__ handling and therefore can result in code that can't execute. If you're looking to add dependencies such as six, a better option is to create another section below --future using custom sections. See: https://github.com/PyCQA/isort#custom-sections-and-ordering and the discussion here: https://github.com/PyCQA/isort/issues/1463. **Type:** List of Strings **Default:** `('__future__',)` **Config default:** `['__future__']` **Python & Config File Name:** known_future_library **CLI Flags:** - -f - --future ## Known Third Party Force isort to recognize a module as being part of a third party library. **Type:** List of Strings **Default:** `frozenset()` **Config default:** `[]` **Python & Config File Name:** known_third_party **CLI Flags:** - -o - --thirdparty **Examples:** ### Example `.isort.cfg` ``` [settings] known_third_party=my_module1,my_module2 ``` ### Example `pyproject.toml` ``` [tool.isort] known_third_party = ["my_module1", "my_module2"] ``` ## Known First Party Force isort to recognize a module as being part of the current python project. **Type:** List of Strings **Default:** `frozenset()` **Config default:** `[]` **Python & Config File Name:** known_first_party **CLI Flags:** - -p - --project **Examples:** ### Example `.isort.cfg` ``` [settings] known_first_party=my_module1,my_module2 ``` ### Example `pyproject.toml` ``` [tool.isort] known_first_party = ["my_module1", "my_module2"] ``` ## Known Local Folder Force isort to recognize a module as being a local folder. Generally, this is reserved for relative imports (from . import module). **Type:** List of Strings **Default:** `frozenset()` **Config default:** `[]` **Python & Config File Name:** known_local_folder **CLI Flags:** - --known-local-folder **Examples:** ### Example `.isort.cfg` ``` [settings] known_local_folder=my_module1,my_module2 ``` ### Example `pyproject.toml` ``` [tool.isort] known_local_folder = ["my_module1", "my_module2"] ``` ## Known Standard Library Force isort to recognize a module as part of Python's standard library. **Type:** List of Strings **Default:** `('_ast', '_dummy_thread', '_thread', 'abc', 'aifc', 'argparse', 'array', 'ast', 'asynchat', 'asyncio', 'asyncore', 'atexit', 'audioop', 'base64', 'bdb', 'binascii', 'binhex', 'bisect', 'builtins', 'bz2', 'cProfile', 'calendar', 'cgi', 'cgitb', 'chunk', 'cmath', 'cmd', 'code', 'codecs', 'codeop', 'collections', 'colorsys', 'compileall', 'concurrent', 'configparser', 'contextlib', 'contextvars', 'copy', 'copyreg', 'crypt', 'csv', 'ctypes', 'curses', 'dataclasses', 'datetime', 'dbm', 'decimal', 'difflib', 'dis', 'distutils', 'doctest', 'dummy_threading', 'email', 'encodings', 'ensurepip', 'enum', 'errno', 'faulthandler', 'fcntl', 'filecmp', 'fileinput', 'fnmatch', 'formatter', 'fpectl', 'fractions', 'ftplib', 'functools', 'gc', 'getopt', 'getpass', 'gettext', 'glob', 'graphlib', 'grp', 'gzip', 'hashlib', 'heapq', 'hmac', 'html', 'http', 'imaplib', 'imghdr', 'imp', 'importlib', 'inspect', 'io', 'ipaddress', 'itertools', 'json', 'keyword', 'lib2to3', 'linecache', 'locale', 'logging', 'lzma', 'macpath', 'mailbox', 'mailcap', 'marshal', 'math', 'mimetypes', 'mmap', 'modulefinder', 'msilib', 'msvcrt', 'multiprocessing', 'netrc', 'nis', 'nntplib', 'ntpath', 'numbers', 'operator', 'optparse', 'os', 'ossaudiodev', 'parser', 'pathlib', 'pdb', 'pickle', 'pickletools', 'pipes', 'pkgutil', 'platform', 'plistlib', 'poplib', 'posix', 'posixpath', 'pprint', 'profile', 'pstats', 'pty', 'pwd', 'py_compile', 'pyclbr', 'pydoc', 'queue', 'quopri', 'random', 're', 'readline', 'reprlib', 'resource', 'rlcompleter', 'runpy', 'sched', 'secrets', 'select', 'selectors', 'shelve', 'shlex', 'shutil', 'signal', 'site', 'smtpd', 'smtplib', 'sndhdr', 'socket', 'socketserver', 'spwd', 'sqlite3', 'sre', 'sre_compile', 'sre_constants', 'sre_parse', 'ssl', 'stat', 'statistics', 'string', 'stringprep', 'struct', 'subprocess', 'sunau', 'symbol', 'symtable', 'sys', 'sysconfig', 'syslog', 'tabnanny', 'tarfile', 'telnetlib', 'tempfile', 'termios', 'test', 'textwrap', 'threading', 'time', 'timeit', 'tkinter', 'token', 'tokenize', 'trace', 'traceback', 'tracemalloc', 'tty', 'turtle', 'turtledemo', 'types', 'typing', 'unicodedata', 'unittest', 'urllib', 'uu', 'uuid', 'venv', 'warnings', 'wave', 'weakref', 'webbrowser', 'winreg', 'winsound', 'wsgiref', 'xdrlib', 'xml', 'xmlrpc', 'zipapp', 'zipfile', 'zipimport', 'zlib', 'zoneinfo')` **Config default:** `['_ast', '_dummy_thread', '_thread', 'abc', 'aifc', 'argparse', 'array', 'ast', 'asynchat', 'asyncio', 'asyncore', 'atexit', 'audioop', 'base64', 'bdb', 'binascii', 'binhex', 'bisect', 'builtins', 'bz2', 'cProfile', 'calendar', 'cgi', 'cgitb', 'chunk', 'cmath', 'cmd', 'code', 'codecs', 'codeop', 'collections', 'colorsys', 'compileall', 'concurrent', 'configparser', 'contextlib', 'contextvars', 'copy', 'copyreg', 'crypt', 'csv', 'ctypes', 'curses', 'dataclasses', 'datetime', 'dbm', 'decimal', 'difflib', 'dis', 'distutils', 'doctest', 'dummy_threading', 'email', 'encodings', 'ensurepip', 'enum', 'errno', 'faulthandler', 'fcntl', 'filecmp', 'fileinput', 'fnmatch', 'formatter', 'fpectl', 'fractions', 'ftplib', 'functools', 'gc', 'getopt', 'getpass', 'gettext', 'glob', 'graphlib', 'grp', 'gzip', 'hashlib', 'heapq', 'hmac', 'html', 'http', 'imaplib', 'imghdr', 'imp', 'importlib', 'inspect', 'io', 'ipaddress', 'itertools', 'json', 'keyword', 'lib2to3', 'linecache', 'locale', 'logging', 'lzma', 'macpath', 'mailbox', 'mailcap', 'marshal', 'math', 'mimetypes', 'mmap', 'modulefinder', 'msilib', 'msvcrt', 'multiprocessing', 'netrc', 'nis', 'nntplib', 'ntpath', 'numbers', 'operator', 'optparse', 'os', 'ossaudiodev', 'parser', 'pathlib', 'pdb', 'pickle', 'pickletools', 'pipes', 'pkgutil', 'platform', 'plistlib', 'poplib', 'posix', 'posixpath', 'pprint', 'profile', 'pstats', 'pty', 'pwd', 'py_compile', 'pyclbr', 'pydoc', 'queue', 'quopri', 'random', 're', 'readline', 'reprlib', 'resource', 'rlcompleter', 'runpy', 'sched', 'secrets', 'select', 'selectors', 'shelve', 'shlex', 'shutil', 'signal', 'site', 'smtpd', 'smtplib', 'sndhdr', 'socket', 'socketserver', 'spwd', 'sqlite3', 'sre', 'sre_compile', 'sre_constants', 'sre_parse', 'ssl', 'stat', 'statistics', 'string', 'stringprep', 'struct', 'subprocess', 'sunau', 'symbol', 'symtable', 'sys', 'sysconfig', 'syslog', 'tabnanny', 'tarfile', 'telnetlib', 'tempfile', 'termios', 'test', 'textwrap', 'threading', 'time', 'timeit', 'tkinter', 'token', 'tokenize', 'trace', 'traceback', 'tracemalloc', 'tty', 'turtle', 'turtledemo', 'types', 'typing', 'unicodedata', 'unittest', 'urllib', 'uu', 'uuid', 'venv', 'warnings', 'wave', 'weakref', 'webbrowser', 'winreg', 'winsound', 'wsgiref', 'xdrlib', 'xml', 'xmlrpc', 'zipapp', 'zipfile', 'zipimport', 'zlib', 'zoneinfo']` **Python & Config File Name:** known_standard_library **CLI Flags:** - -b - --builtin **Examples:** ### Example `.isort.cfg` ``` [settings] known_standard_library=my_module1,my_module2 ``` ### Example `pyproject.toml` ``` [tool.isort] known_standard_library = ["my_module1", "my_module2"] ``` ## Extra Standard Library Extra modules to be included in the list of ones in Python's standard library. **Type:** List of Strings **Default:** `frozenset()` **Config default:** `[]` **Python & Config File Name:** extra_standard_library **CLI Flags:** - --extra-builtin **Examples:** ### Example `.isort.cfg` ``` [settings] extra_standard_library=my_module1,my_module2 ``` ### Example `pyproject.toml` ``` [tool.isort] extra_standard_library = ["my_module1", "my_module2"] ``` ## Known Other known_OTHER is how imports of custom sections are defined. OTHER is a placeholder for the custom section name. **Type:** Dict **Default:** `{}` **Config default:** `{}` **Python & Config File Name:** known_other **CLI Flags:** **Not Supported** **Examples:** ### Example `.isort.cfg` ``` [settings] sections=FUTURE,STDLIB,THIRDPARTY,AIRFLOW,FIRSTPARTY,LOCALFOLDER known_airflow=airflow ``` ### Example `pyproject.toml` ``` [tool.isort] sections = ['FUTURE', 'STDLIB', 'THIRDPARTY', 'AIRFLOW', 'FIRSTPARTY', 'LOCALFOLDER'] known_airflow = ['airflow'] ``` ## Multi Line Output Multi line output (0-grid, 1-vertical, 2-hanging, 3-vert-hanging, 4-vert-grid, 5-vert-grid-grouped, 6-deprecated-alias-for-5, 7-noqa, 8-vertical-hanging-indent-bracket, 9-vertical-prefix-from-module-import, 10-hanging-indent-with-parentheses). **Type:** Wrapmodes **Default:** `WrapModes.GRID` **Config default:** `WrapModes.GRID` **Python & Config File Name:** multi_line_output **CLI Flags:** - -m - --multi-line **Examples:** ### Example `.isort.cfg` ``` [settings] multi_line_output=3 ``` ### Example `pyproject.toml` ``` [tool.isort] multi_line_output = 3 ``` ## Forced Separate Force certain sub modules to show separately **Type:** List of Strings **Default:** `()` **Config default:** `[]` **Python & Config File Name:** forced_separate **CLI Flags:** **Not Supported** **Examples:** ### Example `.isort.cfg` ``` [settings] forced_separate=glob_exp1,glob_exp2 ``` ### Example `pyproject.toml` ``` [tool.isort] forced_separate = ["glob_exp1", "glob_exp2"] ``` ## Indent String to place for indents defaults to " " (4 spaces). **Type:** String **Default:** ` ` **Config default:** ` ` **Python & Config File Name:** indent **CLI Flags:** - -i - --indent ## Comment Prefix Allows customizing how isort prefixes comments that it adds or modifies on import linesGenerally ` #` (two spaces before a pound symbol) is use, though one space is also common. **Type:** String **Default:** ` #` **Config default:** ` #` **Python & Config File Name:** comment_prefix **CLI Flags:** **Not Supported** ## Length Sort Sort imports by their string length. **Type:** Bool **Default:** `False` **Config default:** `false` **Python & Config File Name:** length_sort **CLI Flags:** - --ls - --length-sort ## Length Sort Straight Sort straight imports by their string length. Similar to `length_sort` but applies only to straight imports and doesn't affect from imports. **Type:** Bool **Default:** `False` **Config default:** `false` **Python & Config File Name:** length_sort_straight **CLI Flags:** - --lss - --length-sort-straight ## Length Sort Sections Sort the given sections by length **Type:** List of Strings **Default:** `frozenset()` **Config default:** `[]` **Python & Config File Name:** length_sort_sections **CLI Flags:** **Not Supported** **Examples:** ### Example `.isort.cfg` ``` [settings] length_sort_sections=future,stdlib ``` ### Example `pyproject.toml` ``` [tool.isort] length_sort_sections = ["future", "stdlib"] ``` ## Add Imports Adds the specified import line to all files, automatically determining correct placement. **Type:** List of Strings **Default:** `frozenset()` **Config default:** `[]` **Python & Config File Name:** add_imports **CLI Flags:** - -a - --add-import **Examples:** ### Example `.isort.cfg` ``` [settings] add_imports=import os,import json ``` ### Example `pyproject.toml` ``` [tool.isort] add_imports = ["import os", "import json"] ``` ## Remove Imports Removes the specified import from all files. **Type:** List of Strings **Default:** `frozenset()` **Config default:** `[]` **Python & Config File Name:** remove_imports **CLI Flags:** - --rm - --remove-import **Examples:** ### Example `.isort.cfg` ``` [settings] remove_imports=os,json ``` ### Example `pyproject.toml` ``` [tool.isort] remove_imports = ["os", "json"] ``` ## Append Only Only adds the imports specified in --add-import if the file contains existing imports. **Type:** Bool **Default:** `False` **Config default:** `false` **Python & Config File Name:** append_only **CLI Flags:** - --append - --append-only ## Reverse Relative Reverse order of relative imports. **Type:** Bool **Default:** `False` **Config default:** `false` **Python & Config File Name:** reverse_relative **CLI Flags:** - --rr - --reverse-relative ## Force Single Line Forces all from imports to appear on their own line **Type:** Bool **Default:** `False` **Config default:** `false` **Python & Config File Name:** force_single_line **CLI Flags:** - --sl - --force-single-line-imports ## Single Line Exclusions One or more modules to exclude from the single line rule. **Type:** List of Strings **Default:** `()` **Config default:** `[]` **Python & Config File Name:** single_line_exclusions **CLI Flags:** - --nsl - --single-line-exclusions **Examples:** ### Example `.isort.cfg` ``` [settings] single_line_exclusions=os,json ``` ### Example `pyproject.toml` ``` [tool.isort] single_line_exclusions = ["os", "json"] ``` ## Default Section Sets the default section for import options: ('FUTURE', 'STDLIB', 'THIRDPARTY', 'FIRSTPARTY', 'LOCALFOLDER') **Type:** String **Default:** `THIRDPARTY` **Config default:** `THIRDPARTY` **Python & Config File Name:** default_section **CLI Flags:** - --sd - --section-default ## Import Headings A mapping of import sections to import heading comments that should show above them. **Type:** Dict **Default:** `{}` **Config default:** `{}` **Python & Config File Name:** import_headings **CLI Flags:** **Not Supported** ## Import Footers A mapping of import sections to import footer comments that should show below them. **Type:** Dict **Default:** `{}` **Config default:** `{}` **Python & Config File Name:** import_footers **CLI Flags:** **Not Supported** ## Balanced Wrapping Balances wrapping to produce the most consistent line length possible **Type:** Bool **Default:** `False` **Config default:** `false` **Python & Config File Name:** balanced_wrapping **CLI Flags:** - -e - --balanced ## Use Parentheses Use parentheses for line continuation on length limit instead of backslashes. **NOTE**: This is separate from wrap modes, and only affects how individual lines that are too long get continued, not sections of multiple imports. **Type:** Bool **Default:** `False` **Config default:** `false` **Python & Config File Name:** use_parentheses **CLI Flags:** - --up - --use-parentheses ## Order By Type Order imports by type, which is determined by case, in addition to alphabetically. **NOTE**: type here refers to the implied type from the import name capitalization. isort does not do type introspection for the imports. These "types" are simply: CONSTANT_VARIABLE, CamelCaseClass, variable_or_function. If your project follows PEP8 or a related coding standard and has many imports this is a good default, otherwise you likely will want to turn it off. From the CLI the `--dont-order-by-type` option will turn this off. **Type:** Bool **Default:** `True` **Config default:** `true` **Python & Config File Name:** order_by_type **CLI Flags:** - --ot - --order-by-type ## Atomic Ensures the output doesn't save if the resulting file contains syntax errors. **Type:** Bool **Default:** `False` **Config default:** `false` **Python & Config File Name:** atomic **CLI Flags:** - --ac - --atomic ## Lines Before Imports The number of blank lines to place before imports. -1 for automatic determination **Type:** Int **Default:** `-1` **Config default:** `-1` **Python & Config File Name:** lines_before_imports **CLI Flags:** - --lbi - --lines-before-imports ## Lines After Imports The number of blank lines to place after imports. -1 for automatic determination **Type:** Int **Default:** `-1` **Config default:** `-1` **Python & Config File Name:** lines_after_imports **CLI Flags:** - --lai - --lines-after-imports ## Lines Between Sections The number of lines to place between sections **Type:** Int **Default:** `1` **Config default:** `1` **Python & Config File Name:** lines_between_sections **CLI Flags:** **Not Supported** ## Lines Between Types The number of lines to place between direct and from imports **Type:** Int **Default:** `0` **Config default:** `0` **Python & Config File Name:** lines_between_types **CLI Flags:** - --lbt - --lines-between-types ## Combine As Imports Combines as imports on the same line. **Type:** Bool **Default:** `False` **Config default:** `false` **Python & Config File Name:** combine_as_imports **CLI Flags:** - --ca - --combine-as ## Combine Star Ensures that if a star import is present, nothing else is imported from that namespace. **Type:** Bool **Default:** `False` **Config default:** `false` **Python & Config File Name:** combine_star **CLI Flags:** - --cs - --combine-star ## Include Trailing Comma Includes a trailing comma on multi line imports that include parentheses. **Type:** Bool **Default:** `False` **Config default:** `false` **Python & Config File Name:** include_trailing_comma **CLI Flags:** - --tc - --trailing-comma ## Split on Trailing Comma Split imports list followed by a trailing comma into VERTICAL_HANGING_INDENT mode. This follows Black style magic comma. **Type:** Bool **Default:** `False` **Config default:** `false` **Python & Config File Name:** split_on_trailing_comma **CLI Flags:** - --split-on-trailing-comma ## From First Switches the typical ordering preference, showing from imports first then straight ones. **Type:** Bool **Default:** `False` **Config default:** `false` **Python & Config File Name:** from_first **CLI Flags:** - --ff - --from-first ## Verbose Shows verbose output, such as when files are skipped or when a check is successful. **Type:** Bool **Default:** `False` **Config default:** `false` **Python & Config File Name:** verbose **CLI Flags:** - -v - --verbose ## Quiet Shows extra quiet output, only errors are outputted. **Type:** Bool **Default:** `False` **Config default:** `false` **Python & Config File Name:** quiet **CLI Flags:** - -q - --quiet ## Force Adds Forces import adds even if the original file is empty. **Type:** Bool **Default:** `False` **Config default:** `false` **Python & Config File Name:** force_adds **CLI Flags:** - --af - --force-adds ## Force Alphabetical Sort Within Sections Force all imports to be sorted alphabetically within a section **Type:** Bool **Default:** `False` **Config default:** `false` **Python & Config File Name:** force_alphabetical_sort_within_sections **CLI Flags:** - --fass - --force-alphabetical-sort-within-sections ## Force Alphabetical Sort Force all imports to be sorted as a single section **Type:** Bool **Default:** `False` **Config default:** `false` **Python & Config File Name:** force_alphabetical_sort **CLI Flags:** - --fas - --force-alphabetical-sort ## Force Grid Wrap Force number of from imports (defaults to 2 when passed as CLI flag without value) to be grid wrapped regardless of line length. If 0 is passed in (the global default) only line length is considered. **Type:** Int **Default:** `0` **Config default:** `0` **Python & Config File Name:** force_grid_wrap **CLI Flags:** - --fgw - --force-grid-wrap ## Force Sort Within Sections Don't sort straight-style imports (like import sys) before from-style imports (like from itertools import groupby). Instead, sort the imports by module, independent of import style. **Type:** Bool **Default:** `False` **Config default:** `false` **Python & Config File Name:** force_sort_within_sections **CLI Flags:** - --fss - --force-sort-within-sections ## Lexicographical Lexicographical order is strictly alphabetical order. For example by default isort will sort `1, 10, 2` into `1, 2, 10` - but with lexicographical sorting enabled it will remain `1, 10, 2`. **Type:** Bool **Default:** `False` **Config default:** `false` **Python & Config File Name:** lexicographical **CLI Flags:** **Not Supported** ## Group By Package If `True` isort will automatically create section groups by the top-level package they come from. **Type:** Bool **Default:** `False` **Config default:** `false` **Python & Config File Name:** group_by_package **CLI Flags:** **Not Supported** ## Ignore Whitespace Tells isort to ignore whitespace differences when --check-only is being used. **Type:** Bool **Default:** `False` **Config default:** `false` **Python & Config File Name:** ignore_whitespace **CLI Flags:** - --ws - --ignore-whitespace ## No Lines Before Sections which should not be split with previous by empty lines **Type:** List of Strings **Default:** `frozenset()` **Config default:** `[]` **Python & Config File Name:** no_lines_before **CLI Flags:** - --nlb - --no-lines-before **Examples:** ### Example `.isort.cfg` ``` [settings] no_lines_before=future,stdlib ``` ### Example `pyproject.toml` ``` [tool.isort] no_lines_before = ["future", "stdlib"] ``` ## No Inline Sort Leaves `from` imports with multiple imports 'as-is' (e.g. `from foo import a, c ,b`). **Type:** Bool **Default:** `False` **Config default:** `false` **Python & Config File Name:** no_inline_sort **CLI Flags:** - --nis - --no-inline-sort ## Ignore Comments If enabled, isort will strip comments that exist within import lines. **Type:** Bool **Default:** `False` **Config default:** `false` **Python & Config File Name:** ignore_comments **CLI Flags:** **Not Supported** ## Case Sensitive Tells isort to include casing when sorting module names **Type:** Bool **Default:** `False` **Config default:** `false` **Python & Config File Name:** case_sensitive **CLI Flags:** - --case-sensitive ## Virtual Env Virtual environment to use for determining whether a package is third-party **Type:** String **Default:** ` ` **Config default:** ` ` **Python & Config File Name:** virtual_env **CLI Flags:** - --virtual-env ## Conda Env Conda environment to use for determining whether a package is third-party **Type:** String **Default:** ` ` **Config default:** ` ` **Python & Config File Name:** conda_env **CLI Flags:** - --conda-env ## Ensure Newline Before Comments Inserts a blank line before a comment following an import. **Type:** Bool **Default:** `False` **Config default:** `false` **Python & Config File Name:** ensure_newline_before_comments **CLI Flags:** - -n - --ensure-newline-before-comments ## Profile Base profile type to use for configuration. Profiles include: black, django, pycharm, google, open\_stack, plone, attrs, hug, wemake, appnexus. As well as any [shared profiles](https://pycqa.github.io/isort/docs/howto/shared_profiles.html). **Type:** String **Default:** ` ` **Config default:** ` ` **Python & Config File Name:** profile **CLI Flags:** - --profile ## Honor Noqa Tells isort to honor noqa comments to enforce skipping those comments. **Type:** Bool **Default:** `False` **Config default:** `false` **Python & Config File Name:** honor_noqa **CLI Flags:** - --honor-noqa ## Src Paths Add an explicitly defined source path (modules within src paths have their imports automatically categorized as first_party). Glob expansion (`*` and `**`) is supported for this option. **Type:** List of Strings **Default:** `()` **Config default:** `[]` **Python & Config File Name:** src_paths **CLI Flags:** - --src - --src-path **Examples:** ### Example `.isort.cfg` ``` [settings] src_paths = src,tests ``` ### Example `pyproject.toml` ``` [tool.isort] src_paths = ["src", "tests"] ``` ## Old Finders Use the old deprecated finder logic that relies on environment introspection magic. **Type:** Bool **Default:** `False` **Config default:** `false` **Python & Config File Name:** old_finders **CLI Flags:** - --old-finders - --magic-placement ## Remove Redundant Aliases Tells isort to remove redundant aliases from imports, such as `import os as os`. This defaults to `False` simply because some projects use these seemingly useless aliases to signify intent and change behaviour. **Type:** Bool **Default:** `False` **Config default:** `false` **Python & Config File Name:** remove_redundant_aliases **CLI Flags:** - --remove-redundant-aliases ## Float To Top Causes all non-indented imports to float to the top of the file having its imports sorted (immediately below the top of file comment). This can be an excellent shortcut for collecting imports every once in a while when you place them in the middle of a file to avoid context switching. *NOTE*: It currently doesn't work with cimports and introduces some extra over-head and a performance penalty. **Type:** Bool **Default:** `False` **Config default:** `false` **Python & Config File Name:** float_to_top **CLI Flags:** - --float-to-top ## Filter Files Tells isort to filter files even when they are explicitly passed in as part of the CLI command. **Type:** Bool **Default:** `False` **Config default:** `false` **Python & Config File Name:** filter_files **CLI Flags:** - --filter-files ## Formatter Specifies the name of a formatting plugin to use when producing output. **Type:** String **Default:** ` ` **Config default:** ` ` **Python & Config File Name:** formatter **CLI Flags:** - --formatter ## Formatting Function The fully qualified Python path of a function to apply to format code sorted by isort. **Type:** Nonetype **Default:** `None` **Config default:** ` ` **Python & Config File Name:** formatting_function **CLI Flags:** **Not Supported** ## Color Output Tells isort to use color in terminal output. **Type:** Bool **Default:** `False` **Config default:** `false` **Python & Config File Name:** color_output **CLI Flags:** - --color ## Treat Comments As Code Tells isort to treat the specified single line comment(s) as if they are code. **Type:** List of Strings **Default:** `frozenset()` **Config default:** `[]` **Python & Config File Name:** treat_comments_as_code **CLI Flags:** - --treat-comment-as-code **Examples:** ### Example `.isort.cfg` ``` [settings] treat_comments_as_code = # my comment 1, # my other comment ``` ### Example `pyproject.toml` ``` [tool.isort] treat_comments_as_code = ["# my comment 1", "# my other comment"] ``` ## Treat All Comments As Code Tells isort to treat all single line comments as if they are code. **Type:** Bool **Default:** `False` **Config default:** `false` **Python & Config File Name:** treat_all_comments_as_code **CLI Flags:** - --treat-all-comment-as-code ## Supported Extensions Specifies what extensions isort can be run against. **Type:** List of Strings **Default:** `('pxd', 'py', 'pyi', 'pyx')` **Config default:** `['pxd', 'py', 'pyi', 'pyx']` **Python & Config File Name:** supported_extensions **CLI Flags:** - --ext - --extension - --supported-extension **Examples:** ### Example `.isort.cfg` ``` [settings] supported_extensions=pyw,ext ``` ### Example `pyproject.toml` ``` [tool.isort] supported_extensions = ["pyw", "ext"] ``` ## Blocked Extensions Specifies what extensions isort can never be run against. **Type:** List of Strings **Default:** `('pex',)` **Config default:** `['pex']` **Python & Config File Name:** blocked_extensions **CLI Flags:** - --blocked-extension **Examples:** ### Example `.isort.cfg` ``` [settings] blocked_extensions=pyw,pyc ``` ### Example `pyproject.toml` ``` [tool.isort] blocked_extensions = ["pyw", "pyc"] ``` ## Constants An override list of tokens to always recognize as a CONSTANT for order_by_type regardless of casing. **Type:** List of Strings **Default:** `frozenset()` **Config default:** `[]` **Python & Config File Name:** constants **CLI Flags:** **Not Supported** ## Classes An override list of tokens to always recognize as a Class for order_by_type regardless of casing. **Type:** List of Strings **Default:** `frozenset()` **Config default:** `[]` **Python & Config File Name:** classes **CLI Flags:** **Not Supported** ## Variables An override list of tokens to always recognize as a var for order_by_type regardless of casing. **Type:** List of Strings **Default:** `frozenset()` **Config default:** `[]` **Python & Config File Name:** variables **CLI Flags:** **Not Supported** ## Dedup Headings Tells isort to only show an identical custom import heading comment once, even if there are multiple sections with the comment set. **Type:** Bool **Default:** `False` **Config default:** `false` **Python & Config File Name:** dedup_headings **CLI Flags:** - --dedup-headings ## Only Sections Causes imports to be sorted based on their sections like STDLIB, THIRDPARTY, etc. Within sections, the imports are ordered by their import style and the imports with the same style maintain their relative positions. **Type:** Bool **Default:** `False` **Config default:** `false` **Python & Config File Name:** only_sections **CLI Flags:** - --only-sections - --os ## Only Modified Suppresses verbose output for non-modified files. **Type:** Bool **Default:** `False` **Config default:** `false` **Python & Config File Name:** only_modified **CLI Flags:** - --only-modified - --om ## Combine Straight Imports Combines all the bare straight imports of the same section in a single line. Won't work with sections which have 'as' imports **Type:** Bool **Default:** `False` **Config default:** `false` **Python & Config File Name:** combine_straight_imports **CLI Flags:** - --combine-straight-imports - --csi ## Auto Identify Namespace Packages Automatically determine local namespace packages, generally by lack of any src files before a src containing directory. **Type:** Bool **Default:** `True` **Config default:** `true` **Python & Config File Name:** auto_identify_namespace_packages **CLI Flags:** **Not Supported** ## Namespace Packages Manually specify one or more namespace packages. **Type:** List of Strings **Default:** `frozenset()` **Config default:** `[]` **Python & Config File Name:** namespace_packages **CLI Flags:** **Not Supported** ## Follow Links If `True` isort will follow symbolic links when doing recursive sorting. **Type:** Bool **Default:** `True` **Config default:** `true` **Python & Config File Name:** follow_links **CLI Flags:** **Not Supported** ## Indented Import Headings If `True` isort will apply import headings to indented imports the same way it does unindented ones. **Type:** Bool **Default:** `True` **Config default:** `true` **Python & Config File Name:** indented_import_headings **CLI Flags:** **Not Supported** ## Honor Case In Force Sorted Sections Honor `--case-sensitive` when `--force-sort-within-sections` is being used. Without this option set, `--order-by-type` decides module name ordering too. **Type:** Bool **Default:** `False` **Config default:** `false` **Python & Config File Name:** honor_case_in_force_sorted_sections **CLI Flags:** - --hcss - --honor-case-in-force-sorted-sections ## Sort Relative In Force Sorted Sections When using `--force-sort-within-sections`, sort relative imports the same way as they are sorted when not using that setting. **Type:** Bool **Default:** `False` **Config default:** `false` **Python & Config File Name:** sort_relative_in_force_sorted_sections **CLI Flags:** - --srss - --sort-relative-in-force-sorted-sections ## Overwrite In Place Tells isort to overwrite in place using the same file handle. Comes at a performance and memory usage penalty over its standard approach but ensures all file flags and modes stay unchanged. **Type:** Bool **Default:** `False` **Config default:** `false` **Python & Config File Name:** overwrite_in_place **CLI Flags:** - --overwrite-in-place ## Reverse Sort Reverses the ordering of imports. **Type:** Bool **Default:** `False` **Config default:** `false` **Python & Config File Name:** reverse_sort **CLI Flags:** - --reverse-sort ## Star First Forces star imports above others to avoid overriding directly imported variables. **Type:** Bool **Default:** `False` **Config default:** `false` **Python & Config File Name:** star_first **CLI Flags:** - --star-first ## Git Ignore If `True` isort will honor ignores within locally defined .git_ignore files. **Type:** Dict **Default:** `{}` **Config default:** `{}` **Python & Config File Name:** git_ignore **CLI Flags:** **Not Supported** ## Format Error Override the format used to print errors. **Type:** String **Default:** `{error}: {message}` **Config default:** `{error}: {message}` **Python & Config File Name:** format_error **CLI Flags:** - --format-error ## Format Success Override the format used to print success. **Type:** String **Default:** `{success}: {message}` **Config default:** `{success}: {message}` **Python & Config File Name:** format_success **CLI Flags:** - --format-success ## Sort Order Specify sorting function. Can be built in (natural[default] = force numbers to be sequential, native = Python's built-in sorted function) or an installable plugin. **Type:** String **Default:** `natural` **Config default:** `natural` **Python & Config File Name:** sort_order **CLI Flags:** - --sort-order ## Show Version Displays the currently installed version of isort. **Type:** Bool **Default:** `False` **Config default:** `false` **Python & Config File Name:** **Not Supported** **CLI Flags:** - -V - --version **Examples:** ### Example cli usage `isort --version` ## Version Number Returns just the current version number without the logo **Type:** String **Default:** `==SUPPRESS==` **Config default:** `==SUPPRESS==` **Python & Config File Name:** **Not Supported** **CLI Flags:** - --vn - --version-number ## Write To Stdout Force resulting output to stdout, instead of in-place. **Type:** Bool **Default:** `False` **Config default:** `false` **Python & Config File Name:** **Not Supported** **CLI Flags:** - -d - --stdout ## Show Config See isort's determined config, as well as sources of config options. **Type:** Bool **Default:** `False` **Config default:** `false` **Python & Config File Name:** **Not Supported** **CLI Flags:** - --show-config ## Show Files See the files isort will be run against with the current config options. **Type:** Bool **Default:** `False` **Config default:** `false` **Python & Config File Name:** **Not Supported** **CLI Flags:** - --show-files ## Show Diff Prints a diff of all the changes isort would make to a file, instead of changing it in place **Type:** Bool **Default:** `False` **Config default:** `false` **Python & Config File Name:** **Not Supported** **CLI Flags:** - --df - --diff ## Check Checks the file for unsorted / unformatted imports and prints them to the command line without modifying the file. Returns 0 when nothing would change and returns 1 when the file would be reformatted. **Type:** Bool **Default:** `False` **Config default:** `false` **Python & Config File Name:** **Not Supported** **CLI Flags:** - -c - --check-only - --check ## Settings Path Explicitly set the settings path or file instead of auto determining based on file location. **Type:** String **Default:** `None` **Config default:** ` ` **Python & Config File Name:** **Not Supported** **CLI Flags:** - --sp - --settings-path - --settings-file - --settings ## Config Root Explicitly set the config root for resolving all configs. When used with the --resolve-all-configs flag, isort will look at all sub-folders in this config root to resolve config files and sort files based on the closest available config(if any) **Type:** String **Default:** `None` **Config default:** ` ` **Python & Config File Name:** **Not Supported** **CLI Flags:** - --cr - --config-root ## Resolve All Configs Tells isort to resolve the configs for all sub-directories and sort files in terms of its closest config files. **Type:** Bool **Default:** `False` **Config default:** `false` **Python & Config File Name:** **Not Supported** **CLI Flags:** - --resolve-all-configs ## Jobs Number of files to process in parallel. Negative value means use number of CPUs. **Type:** Int **Default:** `None` **Config default:** ` ` **Python & Config File Name:** **Not Supported** **CLI Flags:** - -j - --jobs ## Ask To Apply Tells isort to apply changes interactively. **Type:** Bool **Default:** `False` **Config default:** `false` **Python & Config File Name:** **Not Supported** **CLI Flags:** - --interactive ## Files One or more Python source files that need their imports sorted. **Type:** String **Default:** `None` **Config default:** ` ` **Python & Config File Name:** **Not Supported** **CLI Flags:** - ## Dont Follow Links Tells isort not to follow symlinks that are encountered when running recursively. **Type:** Bool **Default:** `False` **Config default:** `false` **Python & Config File Name:** **Not Supported** **CLI Flags:** - --dont-follow-links ## Filename Provide the filename associated with a stream. **Type:** String **Default:** `None` **Config default:** ` ` **Python & Config File Name:** **Not Supported** **CLI Flags:** - --filename ## Allow Root Tells isort not to treat / specially, allowing it to be run against the root dir. **Type:** Bool **Default:** `False` **Config default:** `false` **Python & Config File Name:** **Not Supported** **CLI Flags:** - --allow-root ## Dont Float To Top Forces --float-to-top setting off. See --float-to-top for more information. **Type:** Bool **Default:** `False` **Config default:** `false` **Python & Config File Name:** **Not Supported** **CLI Flags:** - --dont-float-to-top ## Dont Order By Type Don't order imports by type, which is determined by case, in addition to alphabetically. **NOTE**: type here refers to the implied type from the import name capitalization. isort does not do type introspection for the imports. These "types" are simply: CONSTANT_VARIABLE, CamelCaseClass, variable_or_function. If your project follows PEP8 or a related coding standard and has many imports this is a good default. You can turn this on from the CLI using `--order-by-type`. **Type:** Bool **Default:** `False` **Config default:** `false` **Python & Config File Name:** **Not Supported** **CLI Flags:** - --dt - --dont-order-by-type ## Ext Format Tells isort to format the given files according to an extensions formatting rules. **Type:** String **Default:** `None` **Config default:** ` ` **Python & Config File Name:** **Not Supported** **CLI Flags:** - --ext-format ## Deprecated Flags ==SUPPRESS== **Type:** String **Default:** `None` **Config default:** ` ` **Python & Config File Name:** **Not Supported** **CLI Flags:** - -k - --keep-direct-and-as isort-6.0.1/docs/configuration/pre-commit.md0000644000000000000000000000257213615410400016001 0ustar00Using isort with pre-commit ======== isort provides official support for [pre-commit](https://pre-commit.com/). ### isort pre-commit step To use isort's official pre-commit integration add the following config: ```yaml - repo: https://github.com/pycqa/isort rev: 5.13.2 hooks: - id: isort name: isort (python) ``` under the `repos` section of your projects `.pre-commit-config.yaml` file. Optionally if you want to have different hooks over different file types (ex: python vs cython vs pyi) you can do so with the following config: ```yaml - repo: https://github.com/pycqa/isort rev: 5.13.2 hooks: - id: isort name: isort (python) - id: isort name: isort (cython) types: [cython] - id: isort name: isort (pyi) types: [pyi] ``` ### seed-isort-config Older versions of isort used a lot of magic to determine import placement, that could easily break when running on CI/CD. To fix this, a utility called `seed-isort-config` was created. Since isort 5 however, the project has drastically improved its placement logic and ensured a good level of consistency across environments. If you have a step in your pre-commit config called `seed-isort-config` or similar, it is highly recommend that you remove this. It is guaranteed to slow things down, and can conflict with isort's own module placement logic. isort-6.0.1/docs/configuration/profiles.md0000644000000000000000000000443013615410400015543 0ustar00Built-in Profile for isort ======== The following profiles are built into isort to allow easy interoperability with common projects and code styles. To use any of the listed profiles, use `isort --profile PROFILE_NAME` from the command line, or `profile=PROFILE_NAME` in your configuration file. #black - **multi_line_output**: `3` - **include_trailing_comma**: `True` - **split_on_trailing_comma**: `True` - **force_grid_wrap**: `0` - **use_parentheses**: `True` - **ensure_newline_before_comments**: `True` - **line_length**: `88` #django - **combine_as_imports**: `True` - **include_trailing_comma**: `True` - **multi_line_output**: `5` - **line_length**: `79` #pycharm - **multi_line_output**: `3` - **force_grid_wrap**: `2` - **lines_after_imports**: `2` #google - **force_single_line**: `True` - **force_sort_within_sections**: `True` - **lexicographical**: `True` - **single_line_exclusions**: `('typing',)` - **order_by_type**: `False` - **group_by_package**: `True` #open_stack - **force_single_line**: `True` - **force_sort_within_sections**: `True` - **lexicographical**: `True` #plone - **force_alphabetical_sort**: `True` - **force_single_line**: `True` - **lines_after_imports**: `2` - **line_length**: `200` #attrs - **atomic**: `True` - **force_grid_wrap**: `0` - **include_trailing_comma**: `True` - **lines_after_imports**: `2` - **lines_between_types**: `1` - **multi_line_output**: `3` - **use_parentheses**: `True` #hug - **multi_line_output**: `3` - **include_trailing_comma**: `True` - **force_grid_wrap**: `0` - **use_parentheses**: `True` - **line_length**: `100` #wemake - **multi_line_output**: `3` - **include_trailing_comma**: `True` - **use_parentheses**: `True` - **line_length**: `80` #appnexus - **multi_line_output**: `3` - **include_trailing_comma**: `True` - **force_grid_wrap**: `0` - **use_parentheses**: `True` - **ensure_newline_before_comments**: `True` - **line_length**: `88` - **force_sort_within_sections**: `True` - **order_by_type**: `False` - **case_sensitive**: `False` - **reverse_relative**: `True` - **sort_relative_in_force_sorted_sections**: `True` - **sections**: `['FUTURE', 'STDLIB', 'THIRDPARTY', 'FIRSTPARTY', 'APPLICATION', 'LOCALFOLDER']` - **no_lines_before**: `'LOCALFOLDER'` isort-6.0.1/docs/configuration/setuptools_integration.md0000644000000000000000000000116113615410400020542 0ustar00# Setuptools integration Upon installation, isort enables a `setuptools` command that checks Python files declared by your project. Running `python setup.py isort` on the command line will check the files listed in your `py_modules` and `packages`. If any warning is found, the command will exit with an error code: ```bash $ python setup.py isort ``` Also, to allow users to be able to use the command without having to install isort themselves, add isort to the setup\_requires of your `setup()` like so: ```python setup( name="project", packages=["project"], setup_requires=[ "isort" ] ) ``` isort-6.0.1/docs/contributing/1.-contributing-guide.md0000644000000000000000000000757613615410400017614 0ustar00Contributing to isort ======== Looking for a useful open source project to contribute to? Want your contributions to be warmly welcomed and acknowledged? Welcome! You have found the right place. ## Getting isort set up for local development The first step when contributing to any project is getting it set up on your local machine. isort aims to make this as simple as possible. Account Requirements: - [A valid GitHub account](https://github.com/join) Base System Requirements: - Python3.9+ - uv - bash or a bash compatible shell (should be auto-installed on Linux / Mac) - WSL users running Ubuntu may need to install Python's venv module even after installing Python. Once you have verified that your system matches the base requirements you can start to get the project working by following these steps: 1. [Fork the project on GitHub](https://github.com/pycqa/isort/fork). 1. Clone your fork to your local file system: `git clone https://github.com/$GITHUB_ACCOUNT/isort.git` 1. `cd isort` 1. `uv sync --all-extras --frozen` * Optionally, isolate uv's installation from the rest of your system using the instructions on the uv site here: https://docs.astral.sh/uv/ 1. `./scripts/test.sh` should yield Success: no issues found 1. `./scripts/clean.sh` should yield a report checking packages **TIP**: `./scripts/done.sh` will run both clean and test in one step. ### Docker development If you would instead like to develop using Docker, the only local requirement is docker. See the [docker docs](https://docs.docker.com/get-started/) if you have not used docker before. Once you have the docker daemon running and have cloned the repository, you can get started by following these steps: 1. `cd isort` 2. `./scripts/docker.sh` A local test cycle might look like the following: 1. `docker build ./ -t isort:latest` 2. `docker run isort` 3. if #2 fails, debug, save, and goto #1 * `docker run -it isort bash` will get you into the failed environment * `docker run -v $(git rev-parse --show-toplevel):/isort` will make changes made in the docker environment persist on your local checkout. **TIP**: combine both to get an interactive docker shell that loads changes made locally, even after build, to quickly rerun that pesky failing test 4. `./scripts/docker.sh` 5. if #4 fails, debug, save and goto #1; you may need to specify a different `--build-arg VERSION=$VER` 6. congrats! you are probably ready to push a contribution ## Making a contribution Congrats! You're now ready to make a contribution! Use the following as a guide to help you reach a successful pull-request: 1. Check the [issues page](https://github.com/pycqa/isort/issues) on GitHub to see if the task you want to complete is listed there. - If it's listed there, write a comment letting others know you are working on it. - If it's not listed in GitHub issues, go ahead and log a new issue. Then add a comment letting everyone know you have it under control. - If you're not sure if it's something that is good for the main isort project and want immediate feedback, you can discuss it [here](https://gitter.im/timothycrosley/isort). 2. Create an issue branch for your local work `git checkout -b issue/$ISSUE-NUMBER`. 3. Do your magic here. 4. Ensure your code matches the [HOPE-8 Coding Standard](https://github.com/hugapi/HOPE/blob/master/all/HOPE-8--Style-Guide-for-Hug-Code.md#hope-8----style-guide-for-hug-code) used by the project. 5. Run tests locally to make sure everything is still working `./scripts/done.sh` _Or if you are using Docker_ `docker run isort:latest` 6. Submit a pull request to the main project repository via GitHub. Thanks for the contribution! It will quickly get reviewed, and, once accepted, will result in your name being added to the acknowledgments list :). ## Thank you! I can not tell you how thankful I am for the hard work done by isort contributors like *you*. Thank you! ~Timothy Crosley isort-6.0.1/docs/contributing/2.-coding-standard.md0000644000000000000000000000603313615410400017037 0ustar00# HOPE 8 -- Style Guide for Hug Code | | | | ------------| ------------------------------------------- | | HOPE: | 8 | | Title: | Style Guide for Hug Code | | Author(s): | Timothy Crosley | | Status: | Active | | Type: | Process | | Created: | 19-May-2019 | | Updated: | 17-August-2019 | ## Introduction This document gives coding conventions for the Hug code comprising the Hug core as well as all official interfaces, extensions, and plugins for the framework. Optionally, projects that use Hug are encouraged to follow this HOPE and link to it as a reference. ## PEP 8 Foundation All guidelines in this document are in addition to those defined in Python's [PEP 8](https://www.python.org/dev/peps/pep-0008/) and [PEP 257](https://www.python.org/dev/peps/pep-0257/) guidelines. ## Line Length Too short of lines discourage descriptive variable names where they otherwise make sense. Too long of lines reduce overall readability and make it hard to compare 2 files side by side. There is no perfect number: but for Hug, we've decided to cap the lines at 100 characters. ## Descriptive Variable names Naming things is hard. Hug has a few strict guidelines on the usage of variable names, which hopefully will reduce some of the guesswork: - No one character variable names. - Except for x, y, and z as coordinates. - It's not okay to override built-in functions. - Except for `id`. Guido himself thought that shouldn't have been moved to the system module. It's too commonly used, and alternatives feel very artificial. - Avoid Acronyms, Abbreviations, or any other short forms - unless they are almost universally understand. ## Adding new modules New modules added to the a project that follows the HOPE-8 standard should all live directly within the base `PROJECT_NAME/` directory without nesting. If the modules are meant only for internal use within the project, they should be prefixed with a leading underscore. For example, def _internal_function. Modules should contain a docstring at the top that gives a general explanation of the purpose and then restates the project's use of the MIT license. There should be a `tests/test_$MODULE_NAME.py` file created to correspond to every new module that contains test coverage for the module. Ideally, tests should be 1:1 (one test object per code object, one test method per code method) to the extent cleanly possible. ## Automated Code Cleaners All code submitted to Hug should be formatted using Black and isort. Black should be run with the line length set to 100, and isort with Black compatible settings in place. ## Automated Code Linting All code submitted to hug should run through the following tools: - Black and isort verification. - Flake8 - flake8-bugbear - Bandit - ruff - pep8-naming - vulture isort-6.0.1/docs/contributing/3.-code-of-conduct.md0000644000000000000000000000756113615410400016757 0ustar00# HOPE 11 -- Code of Conduct | | | | ------------| ------------------------------------------- | | HOPE: | 11 | | Title: | Code of Conduct | | Author(s): | Timothy Crosley | | Status: | Active | | Type: | Process | | Created: | 17-August-2019 | | Updated: | 17-August-2019 | ## Abstract Defines the Code of Conduct for Hug and all related projects. ## Our Pledge In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, sex characteristics, gender identity and expression, level of experience, education, socio-economic status, nationality, personal appearance, race, religion, or sexual identity and orientation. ## Our Standards Examples of behavior that contributes to creating a positive environment include: * Using welcoming and inclusive language * Being respectful of differing viewpoints and experiences * Gracefully accepting constructive criticism * Focusing on what is best for the community * Showing empathy towards other community members Examples of unacceptable behavior by participants include: * The use of sexualized language or imagery and unwelcome sexual attention or advances * Trolling, insulting/derogatory comments, and personal or political attacks * Public or private harassment * Publishing others' private information, such as a physical or electronic address, without explicit permission * Other conduct which could reasonably be considered inappropriate in a professional setting ## Our Responsibilities Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior. Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful. ## Scope This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers. ## Enforcement Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting [timothy.crosley@gmail.com](mailto:timothy.crosley@gmail.com). All complaints will be reviewed and investigated and will result in a response that is deemed necessary and appropriate to the circumstances. Confidentiality will be maintained with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately. Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership. ## Attribution This Code of Conduct is adapted from the [Contributor Covenant][https://www.contributor-covenant.org], version 1.4, available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html For answers to common questions about this code of conduct, see https://www.contributor-covenant.org/faq isort-6.0.1/docs/contributing/4.-acknowledgements.md0000644000000000000000000001660113615410400017334 0ustar00Core Developers =================== - Aniruddha Bhattacharjee (@anirudnits) - Jon Dufresne (@jdufresne) - Tamas Szabo (@sztamas) - Thiago A. (@staticdev) - Timothy Edmund Crosley (@timothycrosley) Plugin Writers =================== - *VIM* - Juan Pedro Fisanotti (@fisadev) - *Emacs* - Friedrich Paetzke (@paetzke) - *Sublime* - Thijs de Zoute (@thijsdezoete) Notable Bug Reporters =================== - Bengt Lüers (@Bengt) - Chris Adams (@acdha) - @OddBloke - Martin Geisler (@mgeisleinr) - Tim Heap (@timheap) - Matěj Nikl (@MatejNikl) Code Contributors =================== - Aaron Gallagher (@habnabit) - Thomas Grainger (@graingert) - Thijs de Zoute (@thijsdezoete) - Marc Abramowitz (@msabramo) - Daniel Cowgill (@dcowgill) - Francois Lebel (@flebel) - Antoni Segura Puimedon (@celebdor) - Pablo (@oubiga) - Oskar Hahn (@ostcar) - Wim Glenn (@wimglenn) - Matt Caldwell (@mattcaldwell) - Dwayne Bailey (@dwaynebailey) - Ionel Cristian Mărieș (@ionelmc) - Chris Adams (@acdha) - GuoJing (@GuoJing) - George Hickman (@ghickman) - Dan Davison (@dandavison) - Maciej Wolff (@maciejwo) - Elliott Sales de Andrade (@qulogic) - Kasper Jacobsen (@dinoshauer) - Sebastian Pipping (@hartwork) - Helen Sherwood-Taylor (@helenst) - Mocker (@Zuckonit) - Tim Graham (@timgraham) - Adam (@NorthIsUp) - Norman Jäckel (@normanjaeckel) - Derrick Petzold (@dpetzold) - Michael van Tellingen (@mvantellingen) - Patrick Yevsukov (@patrickyevsukov) - Christer van der Meeren (@cmeeren) - Timon Wong/NHNCN (@timonwong) - Jeremy Dunck (@jdunck) - Benjamin ABEL (@benjaminabel) - Dan Baragan (@danbaragan) - Rob Cowie (@robcowie) - Amit Shah (@Amwam) - Patrick Gerken (@do3cc) - @dein0s - David Stensland (@terite) - Ankur Dedania (@AbsoluteMSTR) - Lee Packham (@leepa) - Jesse Mullan (@jmullan) - Kwok-kuen Cheung (@cheungpat) - Johan Bloemberg (@aequitas) - Dan Watson (@dcwatson) - Éric Araujo (@merwok) - Dan Palmer (@danpalmer) - Andy Boot (@bootandy) - @m7v8 - John Vandenberg (@jayvdb) - Adam Chainz (@adamchainz) - @Brightcells - Jonas Trappenberg (@teeberg) - Andrew Konstantaras (@akonsta) - Jason Brackman (@jasonbrackman) - Kathryn Lingel (@katlings) - Andrew Gaul (@gaul) - John Chadwick (@jchv) - Jon Dufresne (@jdufresne) - Brian F. Baron (@briabar) - Madison Caldwell (@madirey) - Matt Yule-Bennett (@mattbennett) - Jaswanth Kumar (@jaswanth098) - Dario Navin (@Zarathustra2) - Danny Weinberg (@FuegoFro) - Gram (@orsinium) - Hugo van Kemenade (@hugovk) - Géry Ogam (@maggyero) - Cody Scott (@Siecje) - Pedro Algarvio (@s0undt3ch) - Chris St. Pierre (@stpierre) - Sebastian Rittau (@srittau) - João M.C. Teixeira (@joaomcteixeira) - Honnix (@honnix) - Anders Kaseorg (@andersk) - @r-richmond - Sebastian (@sebix) - Kosei Kitahara (@Surgo) - Seung Hyeon, Kim (@hyeonjames) - Gerard Dalmau (@gdalmau) - Robert Tasarz (@rtasarz) - Ryo Miyajima (@sergeant-wizard) - @mdagaro - Maksim Kurnikov (@mkurnikov) - Daniel Hahler (@blueyed) - @ucodery - Aarni Koskela (@akx) - Alex Chan (@alexwlchan) - Rick Thomas (@richardlthomas) - Jeppe Fihl-Pearson (@Tenzer) - Jonas Lundberg (@lundberg) - Neil (@NeilGirdhar) - @dmanikowski-reef - Stephen Brown II (@StephenBrown2) - Ankur Dedania (@AnkurDedania) - Anthony Sottile (@asottile) - Bendik Samseth (@bsamseth) - Dan W Anderson (@anderson-dan-w) - DeepSource Bot (@deepsourcebot) - Mitar (@mitar) - Omer Katz (@thedrow) - Santiago Castro (@bryant1410) - Sergey Fursov (@GeyseR) - Thomas Robitaille (@astrofrog) - Ville Skyttä (@scop) - Hakan Çelik (@hakancelik96) - Dylan Katz (@Plazmaz) - Linus Lewandowski (@LEW21) - Bastien Gérard (@bagerard) - Brian Dombrowski (@bdombro) - Ed Morley (@edmorley) - Graeme Coupar (@obmarg) - Jerome Leclanche (@jleclanche) - Joshu Coats (@rhwlo) - Mansour Behabadi (@oxplot) - Sam Lai (@slai) - Tamas Szabo (@sztamas) - Yedidyah Bar David (@didib) - Hidetoshi Hirokawa (@h-hirokawa) - Aaron Chong (@acjh) - Harai Akihiro (@harai) - Andy Freeland (@rouge8) - @ethifus - Joachim Brandon LeBlanc (@demosdemon) - Brian May (@brianmay) - Bruno Oliveira (@nicoddemus) - Bruno Renié (@brutasse) - Bryce Guinta (@brycepg) - David Chan (@dchanm) - David Smith (@smithdc1) - Irv Lustig (@Dr-Irv) - Dylan Richardson (@dylrich) - Emil Melnikov (@emilmelnikov) - Eric Johnson (@metrizable) - @ryabtsev - Felix Yan (@felixonmars) - Gil Forcada Codinachs (@gforcada) - Ilya Konstantinov (@ikonst) - Jace Browning (@jacebrowning) - Jin Suk Park (@jinmel) - Jürgen Gmach (@jugmac00) - Maciej Gawinecki (@dzieciou) - Minn Soe (@MinnSoe) - Nikolaus Wittenstein (@adzenith) - Norman J. Harman Jr. (@njharman) - P R Gurunath (@gurunath-p) - Patrick Hayes (@pfhayes) - Pete Grayson (@jpgrayson) - Philip Jenvey (@pjenvey) - Rajiv Bakulesh Shah (@brainix) - Reid D McKenzie (@arrdem) - Robert DeRose (@RobertDeRose) - Roey Darwish Dror (@r-darwish) - Rudinei Goi Roecker (@rudineirk) - Wagner (@wagner-certat) - Nikita Sobolev (@sobolevn) - Terence Honles (@terencehonles) - The Gitter Badger (@gitter-badger) - Tim Gates (@timgates42) - Tim Staley (@timstaley) - Vincent Hatakeyama (@vincent-hatakeyama) - Yaron de Leeuw (@jarondl) - @jwg4 - @nicolelodeon - Łukasz Langa (@ambv) - Grzegorz Pstrucha (@Gricha) - Zac Hatfield-Dodds (@Zac-HD) - Jiří Škorpil (@JiriSko) - James Winegar (@jameswinegar) - Abdullah Dursun (@adursun) - Guillaume Lostis (@glostis) - Krzysztof Jagiełło (@kjagiello) - Nicholas Devenish (@ndevenish) - Aniruddha Bhattacharjee (@anirudnits) - Alexandre Yang (@AlexandreYang) - Andrew Howe (@howeaj) - Sang-Heon Jeon (@lntuition) - Denis Veselov (@saippuakauppias) - James Curtin (@jamescurtin) - Marco Gorelli (@MarcoGorelli) - Louis Sautier (@sbraz) - Timur Kushukov (@timqsh) - Bhupesh Varshney (@Bhupesh-V) - Rohan Khanna (@rohankhanna) - Vasilis Gerakaris (@vgerak) - @tonci-bw - @jaydesl - Tamara (@infinityxxx) - Akihiro Nitta (@akihironitta) - Samuel Gaist (@sgaist) - @dwanderson-intel - Quentin Santos (@qsantos) - @gofr - Pavel Savchenko (@asfaltboy) - @dongfangtianyu - Christian Clauss (@cclauss) - Jon Banafato (@jonafato) - ruro (@RuRo) - Léni (@legau) - keno (Ken Okada) (@kenoss) - Shota Terashita (@shotat) - Luca Di sera (@diseraluca) - Tonye Jack (@jackton1) - Yusuke Hayashi (@yhay81) - Arthur Rio (@arthurio) - Bob (@bobwalker99) - Martijn Pieters (@mjpieters) - Asiel Díaz Benítez (@adbenitez) - Almaz (@monosans) - Mathieu Kniewallner (@mkniewallner) - Christian Decker (@chrisdecker1201) - Adam Parkin (@pzelnip) - @MapleCCC - @Parnassius - @SaucyGames05 - Tim Heap (@mx-moth) Documenters =================== - Reinout van Rees (@reinout) - Helen Sherwood-Taylor (@helenst) - Elliott Sales de Andrade (@QuLogic) - Brian Peiris (@brianpeiris) - Tim Graham (@timgraham) - Josh Soref (@jsoref) - Teg Khanna (@tegkhanna) - Sarah Beth Tracy (@sbtries) - Aaron Brown (@aaronvbrown) - Harutaka Kawamura (@harupy) - Brad Solomon (@bsolomon1124) - Martynas Mickevičius (@2m) - Taneli Hukkinen (@hukkinj1) - @r-richmond - John Villalovos (@JohnVillalovos) - Kosei Kitahara (@Surgo) - Marat Sharafutdinov (@decaz) - Abtin (@abtinmo) - @scottwedge - Hasan Ramezani (@hramezani) - @hirosassa - David Poznik (@dpoznik) - Mike Frysinger (@vapier) - @DanielFEvans - Giuseppe Lumia (@glumia) - John Brock (@JohnHBrock) - Sergey Fedoseev (@sir-sigurd) -------------------------------------------- A sincere thanks to everyone who has helped isort be the great utility it is today! It would not be one-hundredth as useful and consistent as it is now without the help of your bug reports, commits, and suggestions. You guys rock! ~Timothy Crosley isort-6.0.1/docs/howto/shared_profiles.md0000644000000000000000000000103513615410400015360 0ustar00# Shared Profiles As well as the [built in profiles](https://pycqa.github.io/isort/docs/configuration/profiles.html), you can define and share your own profiles. All that's required is to create a Python package that exposes an entry point to a dictionary exposing profile settings under `isort.profiles`. An example is available [within the `isort` repo](https://github.com/PyCQA/isort/tree/main/example_shared_isort_profile) ### Example `.isort.cfg` ``` [options.entry_points] isort.profiles = shared_profile=my_module:PROFILE ``` isort-6.0.1/docs/major_releases/introducing_isort_5.md0000644000000000000000000001203513615410400020035 0ustar00# Introducing isort 5 [![isort 5 - the best version of isort yet](https://raw.githubusercontent.com/pycqa/isort/main/art/logo_5.png)](https://pycqa.github.io/isort/) isort 5.0.0 is the first major release of isort in over five years and the first significant refactoring of isort since it was conceived more than ten years ago. It's also the first version to require Python 3 (Python 3.6+ at that!) to run - though it can still be run on source files from any version of Python. This does mean that there may be some pain with the upgrade process, but we believe the improvements will be well worth it. [Click here for an attempt at full changelog with a list of breaking changes.](https://pycqa.github.io/isort/CHANGELOG.html) [Using isort 4.x.x? Click here for the isort 5.0.0 upgrade guide.](https://pycqa.github.io/isort/docs/upgrade_guides/5.0.0.html) [Try isort 5 right now from your browser!](https://pycqa.github.io/isort/docs/quick_start/0.-try.html) So why the massive change? # Profile support ``` isort --profile black . isort --profile django . isort --profile pycharm . isort --profile google . isort --profile open_stack . isort --profile plone . isort --profile attrs . isort --profile hug . ``` isort is very configurable. That's great, but it can be overwhelming, both for users and for the isort project. isort now comes with profiles for the most common isort configurations, so you likely will not need to configure anything at all. This also means that as a project, isort can run extensive tests against these specific profiles to ensure nothing breaks over time. # Sort imports **anywhere** ```python3 import a # <- These are sorted import b b.install(a) import os # <- And these are sorted import sys def my_function(): import x # <- Even these are sorted! import z ``` isort 5 will find and sort contiguous section of imports no matter where they are. It also allows you to place code in-between imports without any hacks required. # Streaming architecture ```python3 import a import b ... ∞ ``` isort has been refactored to use a streaming architecture. This means it can sort files of *any* size (even larger than the Python interpreter supports!) without breaking a sweat. It also means that even when sorting imports in smaller files, it is faster and more resource-efficient. # Consistent behavior across **all** environments Sorting the same file with the same configuration should give you the same output no matter what computer or OS you are running. Extensive effort has been placed around refactoring how modules are placed and how configuration files are loaded to ensure this is the case. # Cython support ```python3 cimport ctime from cpython cimport PyLong_FromVoidPtr from cpython cimport bool as py_bool from cython.operator cimport dereference as deref from cython.operator cimport preincrement as preinc from libc.stdint cimport uint64_t, uintptr_t from libc.stdlib cimport atoi, calloc, free, malloc from libc.string cimport memcpy, strlen from libcpp cimport bool as cpp_bool from libcpp.map cimport map as cpp_map from libcpp.pair cimport pair as cpp_pair from libcpp.string cimport string as cpp_string from libcpp.vector cimport vector as cpp_vector from multimap cimport multimap as cpp_multimap from wstring cimport wstring as cpp_wstring ``` isort 5 adds seamless support for Cython (`.pyx`) files. # Action Comments ```python3 import e import f # isort: off <- Turns isort parsing off import b import a # isort: on <- Turns isort parsing back on import c import d ``` isort 5 adds support for [Action Comments](https://pycqa.github.io/isort/docs/configuration/action_comments.html) which provide a quick and convenient way to control the flow of parsing within single source files. # First class Python API ```python3 import isort isort.code(""" import b import a """) == """ import a import b """ ``` isort now exposes its programmatic API as a first-class citizen. This API makes it easy to extend or use isort in your own Python project. You can see the full documentation for this new API [here](https://pycqa.github.io/isort/reference/isort/api.html). # Solid base for the future A major focus for the release was to give isort a solid foundation for the next 5-10 years of the project's life. isort has been refactored into functional components that are easily testable. The project now has 100% code coverage. It utilizes tools like [Hypothesis](https://hypothesis.readthedocs.io/en/latest/) to reduce the number of unexpected errors. It went from fully dynamic to fully static typing using mypy. Finally, it utilizes the latest linters both on (like [DeepSource](https://deepsource.io/gh/pycqa/isort/)) and offline (like [Flake8](https://flake8.pycqa.org/en/latest/)) to help ensure a higher bar for all code contributions into the future. # Give 5.0.0 a try! [Try isort 5 right now from your browser!](https://pycqa.github.io/isort/docs/quick_start/0.-try.html) OR Install isort locally using `pip3 install isort`. [Click here for full installation instructions.](https://pycqa.github.io/isort/docs/quick_start/1.-install.html) isort-6.0.1/docs/major_releases/release_policy.md0000644000000000000000000000465013615410400017047 0ustar00# isort Project Official Release Policy isort has moved from being a simple hobby project for individuals to sort imports in their Python files to an essential part of the CI/CD pipeline for large companies and significant Open Source projects. Due to this evolution, it is now of increased importance that isort maintains a level of quality, predictability, and consistency that gives projects big and small confidence to depend on it. ## Formatting guarantees With isort 5.1.0, the isort Project guarantees that formatting will stay the same for the options given in accordance to its test suite for the duration of all major releases. This means projects can safely use isort > 5.1.0 < 6.0.0 without worrying about major formatting changes disrupting their Project. ## Packaging guarantees Starting with the 5.0.0 release isort includes the following project guarantees to help guide development: - isort will never have dependencies, optional, required, or otherwise. - isort will always act the same independent to the Python environment it is installed in. ## Versioning isort follows the [Semantic Versioning 2.0.0 specification](https://semver.org/spec/v2.0.0.html) meaning it has three numerical version parts with distinct rules `MAJOR.MINOR.PATCH`. ### Patch Releases x.x.1 Within the isort Project, patch releases are really meant solely to fix bugs and minor oversights. Patch releases should *never* drastically change formatting, even if it's for the better. ### Minor Releases x.1.x Minor changes can contain new backward-incompatible features, and of particular note can include bug fixes that result in intentional formatting changes - but they should still never be too large in scope. API backward compatibility should strictly be maintained. ### Major Releases 1.x.x Major releases are the only place where backward-incompatible changes or substantial formatting changes can occur. Because these kind of changes are likely to break projects that utilize isort, either as a formatter or library, isort must do the following: - Release a release candidate with at least 2 weeks for bugs to be reported and fixed. - Keep releasing follow up release candidates until there are no or few bugs reported. - Provide an upgrade guide that helps users work around any backward-incompatible changes. - Provide a detailed changelog of all changes. - Where possible, warn and point to the upgrade guide instead of breaking when options are removed. isort-6.0.1/docs/quick_start/0.-try.md0000644000000000000000000000367713615410400014447 0ustar00Try isort from your browser! ======== Use our live isort editor to see how isort can help improve the formatting of your Python imports. !!! important - "Safe to use. No code is transmitted." The below live isort tester doesn't transmit any of the code you paste to our server or anyone else's. Instead, this page runs a complete Python3 installation with isort installed entirely within your browser. To accomplish this, it utilizes the [pyodide](https://github.com/iodide-project/pyodide) project.
from future import braces import b import b import os import a from future import braces import b import a import b, a
Loading...
 Configuration (Note: the below must follow JSON format). Full configuration guide is here:
{"line_length": 80, "profile": "black", "atomic": true }
Like what you saw? Installing isort to use locally is as simple as `pip3 install isort`. [Click here for full installation instructions.](https://pycqa.github.io/isort/docs/quick_start/1.-install) isort-6.0.1/docs/quick_start/1.-install.md0000644000000000000000000000143213615410400015263 0ustar00Install `isort` using your preferred Python package manager: `pip3 install isort` OR `uv add isort` OR `poetry add isort` OR `pipenv install isort` OR For a fully isolated user installation you can use [pipx](https://github.com/pipxproject/pipx) `pipx install isort` !!!tip If you want isort to act as a linter for projects, it probably makes sense to add isort as an explicit development dependency for each project that uses it. If, on the other hand, you are an individual developer simply using isort as a personal tool to clean up your own commits, a global or user level installation makes sense. Both are seamlessly supported on a single machine. isort-6.0.1/docs/quick_start/2.-cli.md0000644000000000000000000000450413615410400014370 0ustar00# Command Line Usage Once installed, `isort` exposes a command line utility for sorting, organizing, and formatting imports within Python and Cython source files. To verify the tool is installed correctly, run `isort` from the command line and you should be given the available commands and the version of isort installed. For a list of all CLI options type `isort --help` or view [the online configuration reference](https://pycqa.github.io/isort/docs/configuration/options): ## Formatting a Project In general, isort is most commonly utilized across an entire projects source at once. The simplest way to do this is `isort .` or if using a `src` directory `isort src`. isort will automatically find all Python source files recursively and pick-up a configuration file placed at the root of your project if present. This can be combined with any command line configuration customizations such as specifying a profile to use (`isort . --profile black`). ## Verifying a Project The second most common usage of isort is verifying that imports within a project are formatted correctly (often within the context of a CI/CD system). The simplest way to accomplish this is using the check command line option: `isort --check .`. To improve the usefulness of errors when they do occur, this can be combined with the diff option: `isort --check --diff .`. ## Single Source Files Finally, isort can just as easily be ran against individual source files. Simply pass in a single or multiple source files to sort or validate (Example: `isort setup.py`). ## Multiple Projects Running a single isort command across multiple projects, or source files spanning multiple projects, is highly discouraged. Instead it is recommended that an isort process (or command) is ran for each project independently. This is because isort creates an immutable config for each CLI instance. ``` # YES isort project1 isort project2 # Also YES isort project1/src project1/test isort project2/src project2/test # NO isort project1 project2 ``` isort-6.0.1/docs/quick_start/3.-api.md0000644000000000000000000000312113615410400014365 0ustar00# Programmatic Python API Usage In addition to the powerful command line interface, isort exposes a complete Python API. To use the Python API, `import isort` and then call the desired function call: Every function is fully type hinted and requires and returns only builtin Python objects. Highlights include: - `isort.code` - Takes a string containing code, and returns it with imports sorted. - `isort.check_code` - Takes a string containing code, and returns `True` if all imports are sorted correctly, otherwise, `False`. - `isort.stream` - Takes an input stream containing Python code and an output stream. Outputs code to output stream with all imports sorted. - `isort.check_stream` - Takes an input stream containing Python code and returns `True` if all imports in the stream are sorted correctly, otherwise, `False`. - `isort.file` - Takes the path of a Python source file and sorts the imports in-place. - `isort.check_file` - Takes the path of a Python source file and returns `True` if all imports contained within are sorted correctly, otherwise, `False`. - `isort.place_module` - Takes the name of a module as a string and returns the categorization determined for it. - `isort.place_module_with_reason` - Takes the name of a module as a string and returns the categorization determined for it and why that categorization was given. For a full definition of the API see the [API reference documentation](https://pycqa.github.io/isort/reference/isort/api) or try `help(isort)` from an interactive interpreter. isort-6.0.1/docs/quick_start/interactive.css0000644000000000000000000000061013615410400016103 0ustar00.editor { height: 400px; width: 49.7%; display: inline-block; } .configurator { height: 200px; width: 100%; clear: both; float: left; } #liveTester { background: black; color: white; } #sideBySide { white-space: nowrap; } #liveTester.fullscreen { position: absolute; top: 0px; left: 0px; right: 0px; z-index: 99; bottom: 0px; } isort-6.0.1/docs/quick_start/interactive.js0000644000000000000000000000313513615410400015734 0ustar00window.addEventListener('load', () => { var input = ace.edit("inputEditor"); var output = ace.edit("outputEditor"); var configurator = ace.edit("configEditor"); [input, output, configurator].forEach((editor) => { editor.setTheme("ace/theme/monokai"); editor.session.setMode("ace/mode/python"); editor.resize(); }); configurator.session.setMode("ace/mode/json"); function updateOutput() { output.setValue(document.sort_code(input.getValue(), configurator.getValue())); } output.setReadOnly(true); input.session.on('change', updateOutput); configurator.session.on('change', updateOutput); document.updateOutput = updateOutput; }); languagePluginLoader.then(() => { return pyodide.loadPackage(['micropip']) }).then(() => { pyodide.runPython(` import micropip from js import document def use_isort(*args): import isort import json import textwrap print(f"Using {isort.__version__} of isort.") def sort_code(code, configuration): try: configuration = json.loads(configuration or "{}") except Exception as configuration_error: return "\\n".join(textwrap.wrap(f"Exception thrown trying to read given configuration {configuration_error}", 40)) try: return isort.code(code, **configuration) except Exception as isort_error: return "\\n".join(textwrap.wrap(f"Exception thrown trying to sort given imports {isort_error}", 40)) document.sort_code = sort_code document.updateOutput() micropip.install('isort').then(use_isort)`); }); isort-6.0.1/docs/quick_start/isort-5.0.0-py3-none-any.whl0000644000000000000000000024774413615410400017646 0ustar00PK!ßgisort/__init__.pyuI0 E=k5:ԢS> mJl+.dٓ@ xKHgJVRJ56{`$3>t8( 4gBG^Dӓy TvU߀9/s] q(^хnں7 %o7g7~tEjL*4ePK!ڞC $isort/__main__.pyK+U,/*MS-@l..PK!KXzSFisort/_future/__init__.py} 0D^%C_"4)"mRŽ,3fS#~Y%E''=e@K,6Bʬkik UVb-0\CnAOf Vph7tƝs«=9W'PK!W0"isort/_future/_dataclasses.py}kwǑw @ BU$9%XE;D 43 ﷞= -3w?eYYA\z?MUY̾ߵU߳EU4ɾ-Ne(j7oWlYWynϊ|{:W뇮.<4|[]ٸE-s=s7Uup7~{WϧU{pҹغ5YB+-L+M[Tej~ SZMa=( U[0fPŚ`86;^?߹eU/',|kv~ŕkf|ͲA?, ZouOW2}i0`]M C?yUlU` 3l Wm6N]@\ 8GY9ݶ,JDV47O;ώ/|3`of A?g_e%h$Pa siߡowqɕV__ 5=N{J{X5E·i~Pq6M9<ijz3{!Oz ~~mƄ{DLI`&_2|R5ESCȰ-&ѱN O(_P)@U$x,[/:&041$w:u| e ge]-S8Ѡ 'lN̽OVN_s5!DFZAᕓ/g%c6`^^C,Wd8ɀi.c81%8= "ImQBֹVʹ 3r a=ҿ쬒V n%d}!?O-cHP,=6b^(-t!N5rӁUF³aaK]o`1솚~Q2="$k*߄7Z cNY?G93 _V_2~] ?q'۳Qlg%q.qEPؖmyDr8 R8~({*f( /3h:NhY/fA'ݺҙ @u2,ٶ|A!h3 ˂YsRz&pWbmhNwP=h"5JSO@f,[ +?TRvjҝ4* Xyg rҨq@jݔ+K_--༇oQ? p@3_5PXh[s ߾-2Ò3Dzl u>?YxKBcni3DLx4`YP2xafGG8E#k7+" ~'/:R^-pO|4bd Z5vݫ'/sSRz}Ւ*vgJDO{)X 6:oS,̞ 5VXG8۳f!ҴMu_~oRh}+糓g_>aάvh+7ooGl OD?}2wn3S_&R*zrl;I5=VbBdrcR$@xV-0HqK5`CpWٹQnsb@Īp+]8?1`!Fs4hm->;X W~4eAXe+;„yDܩ6f.<ǃxgfU Fذ7n /h&,} `:&PZdžyDWX+`;&N-}-LHw qQ s0"+{Lg^B1}!C_,JmN ^GB [Bb&&z'ʕ#8(֛9t9jGZ z<ap73:,&|Ç\WAQH pHE xa*( yKGPI(9߮,Ȇ?cY#iJCcp dqaE-paZHNcTų 3e'lCVl㿤/F?YQ2Nнod"ږPCɽ}:2W\LA2Ώ=Rw΄OCk{)f3uM_!kNAWAl0^PV { ի" \;#dBrU7=$nkcI[AE%ZUsVh{-lxH$1Rמo'tV(z%-8j'-nIG? Iȅ)vg\TcƉf/cigN DlCu Œ#ӓod6:G z͙Y$Xmɸݢ 6Zf*7D~ Q#X7!oi w<'ƀ@ AkrIA74lK̖2)$6[:t>aSGE@!/N{04vf0|HjS4LގD*dɧ=eC31QD$&3B LY2D *"6+Q`+tgxulo5Cx5 -Q9]j rLl/[IyߤcLݝOJ=O~tD*@AL+~_C(ZDKO(]e&xbk&?s-[[=UDd#(YWM0&rBFk+gaɻƱb* [=)3>b裈Ǹ{'AurAM6Շ׎l=UVfdi1 $@iߦ;njgr/6KFfYW Eo(7$ł%vFX'yD\TeXyOѫ\Wa=ȕ{ O搬ѢЗulUk⟔˥M¥v'JϛuxJ>;9V 7qCG=@`[n9=FVd@ɂqF{'6,{3O "o'=D?*S-+std'P'ʆp3ёfNHf3Nq 0Yn^/t|ͦg G44Bo0@wZ[Eb_z)9F<9Eݴ $F{8o> >aD6|.=P[(- 7iQ_0ˍgjB*>BFZY2;;{$^?]].B3XP=EBwkS՛53':&)c[ufpF}stK{@޾Т4UAnA8AUV68O2ݽÔ>v`o1 ӏ-B֓zFXVOJj0juuĈ\Fҿ@>^7 SCyiؘl84QHk44~$~̇>ϢL3v0-axږd1|-Btf+>1@wTX)??S@߱qG[I+Ȼė\ck/++CGBvB{/*pr舏߱TO^I~6MQ\i$&+Jy~va^|5y<b4aGO?U3Zqz PdzGaP䨑:td#c rvp/d)0EÉ]dQY\Qi:|7ꑥzQ`/+RO='zrT5:. H=$9)Q49H~*;Yg+edуK*zLH`]9eUнżıN9*Jҋ MƋ'{VWQJC2eSJCfv_BPmRXX9Ec##S 90z7H@9|>c鷂IrK=[lEȝ*Z#ԙXی,%]eq/hl&xlNx`y]&_+ݰS34m\qХ42OLtC jσҰ_?mF!H+RF/H錹.4š.1|ҩ]BnPq4@ EڳTIj!4"ћ̇D6S8E5פgyn 0qc4uWqvۦ19`Q R=V6 ?< ̠gʈ=a'Yel""oQܕgj*pb!y|10i&|cD Væx:8 ;l bUQT>'`X-4_ ׭_܌}9d!'ܡy'.sXcu7ج sWp27_ܸ;EP\ ™׈yc?&&(@-~3wfi$`'%29Bs.#,XoDz'R- `dY 2,c=֖s"2D4ѻ }D!ՌRH !Dݣ7&T!0 6 ├[8 vxbʿ#x6W:VBʤc{dL+ 躊>:61>Nri &sTg],,?l$idהG&"PAbh$m·Q+nڞ&vDbՅ1_ _k1*wNO0K°؜eOy:  n"!qD e/ȯf 4C܇(ƛdZ_:B_חC.6,Y'>gonnp#D{ ]kY("!^Ѡ1܌WI: 87䈖 OCBB>}=~L/6xM.  t~}k"0<V-彃 e(gGhBNxcL&dXٵtoK F@ZD3@P"cR%7ʋ.g>z#HUi&Gb1"Z<[9!(fXP'ԓC("$;## H0(v Y EGQ!ŒC4\"yNO#:񳈼M =h<,jF!Gm0Q?=  Y )X:T)e/}FX:ى_|W ;L8ۇ$ol- J}{]LQ|!ͺg&5.1Jh,Tx*/m; jWGӷ@7mw7}Ap]Ãus/~DJ}fI*Gy(p"%s5@iD9Yݰauc ۠*_g+Z3D%qv҆*{msLhryzucÖ8 AL^(!@NjܫPAơѽh .^6,0`f[Q,[cJQ@g.Wqlrf0cxX8X:'&b[[O}d;9Jg039lTzkD-u]WٛGG>zۉaKP1Y@5 Tf6NeIMOn_G=fS|_O3Ub u}FްC͎~m|2/ )]Z,frrm3sI!K (=Hb;SX" O~ζ@=q٩LCax,ẍ́iӰ(,>C` f(F=.q;QtI$hV Ŏ]k8&*j6w֫}~bm5 xղ$`&W#:$,ro@ڐ(9"2'̳v2mWO'0B~g%RתeL s?1Ejn/]RݧL[;Lܘf!]0 aB d( wҧ/&2'ٌgf9죑;]4M 62-iFc|D񄮍PRC[=W7j+܊BM\:+aW[ ݃@tKY#EpCtɝQL{5c1~Qܺ scZy dp|<jN4VdOςͰ AZW1FQEXI)5yۑZomo3e(;hٙ9ci%\sysòg+3aKI H]>/K?@trs)@>[DDc<7&֍dY!{N3鲚oȨ & KQ2_L^Lq2wFxGTE`֖C0D1`6Jg<9qSQj;OjT(I6bTuAv5HJ$סNB .aN!"4-a6VIʝI`t wҘ6 +)ysNIۉ܆7D y$אe,C Z0 L{FP#3]IΪU ]/ON# X. C>FeN`ʦ6 j:J,0 5$bpoo  =_B뜅vQGr25U&nq7:^{Ya UBD-nkH^s?dW0R2״JqжbZ8Ի@4U=S@w\=riթ-'HtFOjk2)_]PԴ^58c^XNˆ+E! Dzs-L0Y1ozm^!oOuFӗd4*v=g$U 7Vhr7Ȋ>W$̑.X~Q£M6iON%+yt JE6?XTC7[Qq6A--xGggЎˏ h}AAI!/n8eSq>I"SXm>M/TDcnszx5<]7G7z~%C atuc̡c-j!J6Rvma}] 1 gأ}\үS̷ ݋pL '[xKߝMsuLkXEH9V62F|kҌCo0hK q(v{́o @ Kc?MbE &q-hAyNMm ͓C>|G Mqjy'TT/yw06ыs H%R|А'>Tl ^ ⏬_UޕH^L_g~JryeXzj{Ņ^s1cȨx=)‰DnQO8?XF!v<~;Q$#Dlba|muyGɩgǿmŌ i )&[8=>N j(~7-(%eG\~EOx]L%?`ʱ<˅&i[ߧDMg9r[+=/%ow4V(/.hrq@t3-Z?Dk7K{,yPyd1lߕ$]_t=vk~& cIC'<)i^G5A),ƞL,iDo@\<iy>cَGPzo#sAt)bż}ݩo&軈 `sSL]\ KbXGw)e'@P >]R r@NX%WM}'^tN=4]oק 8e3nM'7mhcOG-Ժ2LjWcaw?WZ>BeD= ug H^@qpVḍMen}|ut 0`e2h7=a>.` =&@'82 a4hhag&}zԃt(.3^%M}y=tF;f=Phc4ؖ02ucG텁'!:lƝϠ&#%gm"X=yn!'Zh(Rk'68x4Lpe/&P>8Z|gQX% |\J=K_Rvv0䵞Q@1vp -r%@P^.nxM[٬Mءx<@^<Y,2?+%Jʥ,f!;\Q_'CЦ"@IQZ C>l2MARF79WPmTU[bEE"+@c9Q1A[5*L2>ř Ms.,߉iDŨ+A)Ydc^0C7Ȁ+YB\g։s8Ъ"Ba!xXx|PK!RE isort/_vendored/toml/__init__.py}?k0"ҡcd4mhպbo_EqJA=$!qJ}-ooő"*IÛ$K*kbL=aߠ5HD 5u!HlDMm(61/m'6(9Aˢ1B^PĎ9ԩO#u@n|_y.o;;z /j%*Ufutp+)yީ޸jqkүRo PK!e Qisort/_vendored/toml/decoder.py=ks6+殆Z:ۓCg+TMnJfnV(s, IiI_?%;wǪP$nt7XmKyWt]qTwy>GK6QeU戟OnQj]Ѵe]jU'_'hz5om\$||T4yQn .zۮqkh.V9y{tt,V|Ytu7ͺ\Fazgw.BŘNJʶ.l3%&?m'0jnTf4/s ][>n+ڱEj%B ͷE'RG~u;Yi:4Qz"w5\/_4M\?z[-Qq]lAW?rׯb br]mX֤䫫Mr~<hxۖE3_oVQC%L^*4I`vY[W};N5XZLCj۪*'\29NLzMeErB5UY-tmBߓ I l*NVuswa茹%^ώGԗgng}Ycq_jfЇ&˻뛢MkRmE3N߀QI~߂Y.\ Axe(ep4ew3 :2DlO }WUG;ۂP5jE(ޖR:]+M=C0Lx7yG2jj$h4I}QshtMc[-`oʮ3tP8] k+@1f$(FU9յ#7H2i~lA s'0c,4Cƫ lpqݭrҚU &X`]]R£.2;}O+' Ncκ mtO$B2Y:#gӫ?NWĢ;;^٢&9SXX}'sºΗJ @CWsC]SހT0.0$;H8sh;jymq[Mtb MQi^)+Pw]o,%LPE{ ȼ'IV8 )Uu6` HɢBCS&o qܶʰ<%)cSl`<ĬCx!399I~ST p뾬~L٫kEg1U;HKJ k, 7eۡie?=t7Ϝ掷ndU,"^8e6֐âZُ򎽍ЩKy=Il:-!1GgeB,7GdF.j n #>PҢ-Z{BnjQ~a0>H~$K?U.Lg;y^yFa{kI Ba =OP|rDCHE]1Wg*J06..iX׮q|C!,1t\\uMP3.VrzfUjx6vPâƌzCOw vu u95 Nb,ʱ<8ؖN72󛾩KH 9fv<{FbXDؔ :~fFsU 5>hZ DrbdS_:W7I'-vL*6@QNϛ(gdL A:=`b'3ڈ7I.FyKbM~M.x.! 3-\ɻA^dP\!4UsqSdkYPed-'W_δ~qr+f((GWE&Q k';o[@1k1i ͽVd?qGժZ  d6ʎfSO|++Q;0u;hf 4iC4+ {6ij}]eԂjXt^Ws.lSY ЉaXl,)Zk*,G"(}UB $2a#_x1J4u88iZ.%q(D=}Ѭ=,ٕAUNB};Y}u+ZRsa_Ⱥ)&כ("1m5}ݬ'OS>jRġ4H€-ýQ%JOi*~tT+}7}e(!S,g.ON0v_uՄ,!~vfZ ӳӫ=8&֢ok&lz|gӳ |1.(|}pv'Nd{R"E{o6ۍ^wi`Z~tJ̾1t91z"xkpuG 8R\ 27rcͽ>Ø32|~> Vn^@< 7xQa|4Z@2@;MЁn< x_~/A@?;of&Bůۢ.r~KzLU'-ff4٠⁁I#n1hs 5XI3qrH(,QmRyY* G!ŀ|opVo氝StY `()Aozqجsy\,i5 z N6*VWn0q`xS~z@`o7 ah>]v'un-t?Ncy":n8q{ O߀"d0*)96>]8=]0a`L*(BQ;zT9I5jFS`zd<*%~(F]J?iDN>֖.ﶔD'/}Z'o u0™c(Ve9+3 ٘49rh&S%qg/~ Rt'Ҷ'a}? A_sTf>c;I `<!":ņy,uϧP`E6$̪cR <`= |1MH}lVY^N`Z)A.Sg#)aZdʔ*+|k_aݓq U`P䝐Lm0gxchINTT!K,gqOX/r/loeELd+)@;=Ld͕AH^=  K[vjA26H P1n򅎴&W CY78LET9 85'Jp*9=5|ס[hT|;}=r16,-96&kx=Ta<[t.e8X[{}+"]4U/Ķ(hKLxhg TvS[HzC#;8;|].'/(|YxDp@}FEP./v&(IQo_ZRlUp3u50hv;gھưv=AJT.øep?q`L+ g"1P4;& 8iO.d:Qwo{7|SǘrGx'INv^=SͿSw;s_)= C0LZ: -V0n\.8X/ Szh^4EN__P45~ꍾe CAB4-48pYAGBz4~s9?\VvԓRҤE:}ҡ6$2\},3&"xVPWe$ƒ nT0.i*z ٲB8NBu^ iFN%ZNy2"t/V!æ=5cz!>&'dd+ֿ5a`UسV M>2h4^%Be Nŝ+**<5j}(pREud.lHٞ[l\g'|p\>"*/GU7%E =kЬ"H)Ry3Ēl5ܥ8Lz܅kq9+ ȧP^DGn8q |01!>JϼW|4РJ8}jcա (]Tř,G} 8 ՘;w{x '``>6kӈK|M.yj,z*DeH%L}bsil"n*rPE+}xgϫ[79}_$+쿡>K=`Y!* '{t4_WP7ʹʅծA2S=<"CE_Ă(>ۉy|yC9V=e&-V ??x@c{0eGnpso}ʻPŢ >|9tKY_'ґxDyw?b_?S}MG*NF nZ^Eߕ0Dn‰j~}+/+E <! -R_;w@[ w^~ l71MLcc2Qqd=0* >z/V4hN8KZ[GGPK!@kt{ %isort/_vendored/toml/encoder.py]oF]bB$,1VwB hS @-WJ'fC2KR/%"m'v{fcPJU,y$׿UTW]~H fֿ?'z3]qE.EzU]={r)Kf—h9aiD؊UL&߳9qAW?I F hlXZZ R >!ȷ8K Y\"v0%Aj򲖊pY}5F6EƮ8+:T#]Kȱ8isqMdAEXт׍&i.ZLh'U)EF˒,Nս!h]ܗRD q%T@8dCyʴM+d-:ge( -RF3 "AX tІu韊 2+\7U}ҋ@dݥKѭy=Ŏ:n$[OrlN,x?=! RSUl<xu~~vD@bO&궧)H_r,&ze>۬6ZLm t6ڍo<`(-}Pjq,ìtgtP+@2] ȖleW[8KH'ɳPFڸ3E5+?@Az=c+br.M/ծ)Rz!&h,oXtX[~(m* 8~ |6 |țӅmߘBDKʞL^2 Lew 9O38Ōߕ)c}yj on꺬ϟ_Cmb ykzzE=ׂI[kϬn0I } pp 0p s}m%Y=:`Hh,P> Pҡa vyˏ6TSQM09Rkz24eR[cEʭ8Ƅ vl^4PpnF9%hɍ;TKGUCd%D6WZ_HbBzqMmXhmƪt3 + WZ !hݦi T7ZJYYfCcgmx )~w?o盳Cmz? aYDZ@:"t3ch\!Kyx~Dd~C:*C_fPtO5NCp4cw+N#zftڟt3i궬0 N%ĘA$>JQzz&'m6 > !iT pb+Y6o }X; HuG/@ZxLӶvkk1ᱎXՃ<ڊ)ӌ'_V8v/Dm92kO:H̫V('fONrjzӵ(_`d']CB}C. \#PaN\|mUx ^mKp_n GJ`C!4,j_/?x)ɳSZ#!RcA^=*RZr^Ek;]6}@ſ4Cwbbc[F?PK!NNisort/_vendored/toml/ordered.py !D-=8@K&tACG]Hfvfy.KD#!^RAwrfyS\/66 04 ,edSf6YvH䓯DppGU^{PD+n6Ĺ8G7PK!Ojisort/_vendored/toml/tz.pyj0 ~ Sac@N{QLhV(!qSd~;mCH h yr 5?plt '?}w㓣wglƂ\ ?Y1 dĝ$WS)'xU#f>=z>} dE\&!*qʮqųgbeJ03Gt+[048e-lgc4<Cw 8NS?&d@c ٔa"J \70`k ):Z S- 11@)ˮG gSˢ&hoY#vιW ]Jf+I!#WyůXd۬)7i#Uj jq$R(x r`?NѴy[R+PQ &#þ>Lo,Ŀk9AXZ6fSfAWk& vC[g3h@( ^䂂4?@|緽B+<>B;t 2<XJ~nT ߑ å{o'w b+b3;Y*0D8 Y I_69(`@_Olgm=|fӗF:#2gabTm/h?B#%\ R̈́ᔁD` D%Qd!(\Vd(B nEVy@MVc6<՟CzS-kw8> jzQݍ1E6bBҍlkBehL#{z=ؑ=ŘgnL0#/}○5{Y,TV6ԃʔPګj;_vQ6yt0D=SX~8thmv[od-uBhcHJ媖R|r#@eV{+ vh%%?*uuŖ @{QodCdFy/jf@!W6擅ُGggS}`Gu|e'%֢tLQG޽}b (j   ncd\kP3Sxcڑ+LC5+yyCصz2kשiX56TeTe{D%qFY'b?̯_iٴZ1v RFk>e,S~X\$=dN S+-ưNx@D7G§EVlC#ӆu[;SXj5Iǜ$B&&0?pP薨F9*13DZpG82V@zgզ0_Ua#!O  L Y?K"-8qKZة$=PR M_ݝFV e3թș1xbŶN{k,BwU򪴢*vnT)bl3:[QE\A㡨gpp8jRw#Ǟd5ex73^e$qg҄@õOZ7'l'ǚe|@[$x͐$,6H*!]WMWc1Q9&DyZ9!AX@1h4cѷ"l6c/DFhy(ݚPxr3Gkj?G2?5fdbҞR#mYNo5P)ݾ8?_^cgRoB7,_a`̾6bmdfBQЋx=TymAyBo!Oi~\)C`aӯsv,-J?P/`))wF"^htoam䡴o-+j_mc{iIjtp#u(Șw,iL!Ass}n |~ibaʏ8㳩E&uNS%ʲU=@hO;"[S/: jf+֨; 갰 5(3kʲCzrAZ"\|,xqPl|<D޿4V@o+w O%200DΕV]){?)U_[hӍ┬RwD)W jv%l]5 o.7Ր~.^˷-"X0baI&8 (H'S FgRcp\CisU4!6)nyMk6L ބ Ϗ7L c5xxW6;:1Vt'34;WN~7j{o3by~) kIiQi8ao~^k,D?g 6 vm߶̣8!+lڲYzZXF9;,GTGyX;T 2Um˥@%H }XGЀ$PkV` UA-`L䯃hV brNv@j5!3 Z`1_ 2х$URl/UNU>O;hxve ʈD%.R,R hcy:C^)1,㲞=PTSɪCѻ^ pEe/7Y e40}ы%}A iS{):9创DB[[Ϩ'ˁjrגa#.n"{UB HPK!isort/deprecated/__init__.pyPK!][ h8isort/deprecated/finders.pynF_1l2+K x4F];nġŘ"Y5{܇3/I$9>6ApTTm;ҷ$G˞ttuE%Mu4#:[TAS Sx.EEۍǺ&[錯ʋ라W$/+᧏>oE8\^~QE_e'Gv,@jǯz.;zr MSTa'丧m:/턜5hϴ &/ \nÉ6;^ٿO>kB>6X,D chѪ+$!(P_Ц'm#IrZW>jIZo_-]ѪF؁aSX4yQq@QY'0\.e/7F39I*$ ;Z½x_DDvɨrx X̡pz6~Ʃ΃2'K_+ͨM.UhƴVf,RW+Et3&g `X Vݺ$-KP#w<YBRs Ţ?Tu?pwW0xDCwۀ|p*4l:ф"q@aҴ_ըbz @Oϒc6Ϙ]Yє邅&EKo:LeHTb_>TP*r `tÀcD)AE@obNe $#[hL3_'BIyq hI+ZOW;COH kz`/f } e"y-;:~3̵￴!ƢcUwj&ma%AZ/! 6Zl,zVM1%}@׿4Bh>'Ꚇ`V 3,@Wh_iyXCP=9KWV0SZ )]Qq]DӘm^͋ju'I %/RvBz܃:mB4Fh"qLn_Դ@@,x ߊXi ~?>I2=p}p!Y =:#`2+ _7CMAC^;+Ani:˅ -R-,)]hOnI;]gtuSŽ1Uݮ\<.f ܌R}BiWY?K4p;|3TkԄ#?{eF g̎GXM [j[nDž'ŐNFU)ۜ矁'[h¸E]whTxwm-M.#@w]ϦK[W|Dк-9)\NO/p#H W穾'H.i[Fڥ:G]3&2vD{rBcA@ 8Sۙ)Zl__ O/zui*5 ~`$=O~¬ׯ_$˜FdvHBI LV^-; A1$庛rhJqt|~qֲ 2/4DM^}ڕ[ڒ]Bk^MaI.bsf롔ǮԊ6t]B\._q,ig䒣쨮TnedtyڂY<u%.1aCWa*Cr3(WO2Ͱ.#A\MLrV CXp )k 'jFv}B3}NzwBT[~7YnCzbX(wdT8> zQ4(w/ō9 nlXĶ0xxdc/Hlb)/{jFd)s ڢ; =ucB K$k@SВD lT:=[n/6C7/;06_f%Qj[Ir $`r'Rx raT5*Y[E`1TMA}=a^5#[xn]`)H!wSUmħw"szd N+ڄC˅$^0q{Ȓ8 _%Nt07Ӌˣu9Hp;=_c5llD4[S] ?quX?PK!kbT~yisort/exceptions.py͎0<(H-z$2Ďlо{vU)$I(mSI91֒4`* "X*Ԙ$ɤԪժ7R:Sq<<@P 0{$+ I`]ii`lqٷ߯LA+^Jc$o{lX \{`9D0dZZ=gz;7ₗW8t+GJS Z.4 ZlZsHc>:]!3;ϬPbqSuHv-{nY(Yh!OQ%)pѷ;辪Aiho'!ƫ=$XJx:Ƀ\QȌޱGdv%#AᎼh] ?*x) ?敍 @͵ՑHHRi._R|{a{] oh+o Oe}cy ha{aoP\9@(pq<)+kXT/b@B~1G4k'D; IDګduFX\ˆ`v{S!4@`]z,t,~.%ȡeMnﮗPxLvĖ 4OD>E2ѰfkMqBz0լ{ж۲mȞ%=*p+>I<0X*O=BjZ RtwZ5kS*7vCkCMdMrfBgϤD!򂬀JT]EbVBtOeȡN~`5}#zIA*J_$&Yɧ:3s^Ar vRESiU)?Aun5 ut{q/E< x.@Sj -13A7z6#*/%<'V [W\bPbph_}>]_^<4B3a9zRVcX,"NcNk;ʡrvf#=sHyu@1kn_,f&e̶(qbɚ7&[.juSJ2eUíbpkn"'ӍnFz&UĢ 2>Y!h}(̪I4'mvEebm'&3<ɝ[Y{CA9w6c?1gCI6Z'N!;bEQB JVhJe< >LeCR{S2Jp/N"G`CQǤj:d Uڔ!$dAḆiڊ:B8Uc}KQS[6ۨf?Zۢ?ӿuS%60|[̴fԁ"`SL\,{!iv͵Oi~̱60s dRjSk|i֘[p[&k;;7-6CDajr}q0r!:Ku~N3n8i{t_5H>r-bkҸOMΪ40gAFk:FvDҚ`PEz(PK! isort/logo.pym @E7."Z)h%<\ф7E4s8< jnP_Z6= Zf$eC SA{'4r}MiH i9Y#\Ñ?jЂ$՝]W3--б8q8=G_Y~fvW]e RD'>bŠhouOPK!a3] isort/main.py,gע˰>ѺvBeKq)?g?a˂&je{On(yCxMUTi)pHW3Jih9ˑ0 k%H2}XK[`{M -ndaxr5d:ʏ$5* hM$Դ>xvz<}si"[Àzm,KNjgo._<^g/fǧN?O%|yk d꿲p2\崊Av $ D_jqJ_EV0<0UnB%H@dU盿,6K=~_Vޞ>oO1kO5>Frg'"s DEEmx#VR_F Tl-ʭ5IlNF{J#Ŝt& O2Ceb QU2-E 1?*`1jLHyF@tq]U0A؅8SD.J݁met zoR^)ԺQ~eb߀%{FaV&9=M1 `P%u'|F&1?I^i0pd COp͞9 R!$3?y`L*eM}{25͍>!W<"NXaIx];CٝVrГ.oghiVg_5ggSKԃmݹuEKlvM2L QMbEDwῆ>wzBtwoܲ]n:)'ƔA&*Ja :YߦTQM >ՋY~ GF3BUE$!ҋ7ڀYr4JA4!5}a Wp-Okb5@L0eQ&[<flW C9ANJ"Xk,}õ/ӮPB-BqI748ơXz@b`>if|d2fPil'bgY`nXF"=5Sqf&l2NQS8^"Ճýq]wP2kva#ubu VJY@_LHlxZlh.~KƶC&r|A5kIHGށ@&ۚ=J9-4(h4T48|f{4B5a"g`$p *]3RJinT,EHI[L0g&O1(D^`Sd{/ /axRajǽ&SӢ0z<"ZWXr9u/ Ӏr4!GK0\RCQ+dYtҵy&NJ=)]5IPSeme4";dwL&cj}M3ٰZv&YyHzf>Rn&5yݏ<ފ~q K#!mZC{RncHͮ3m؇{( s}9z4&yd8%FEl*ZtJqK<GwcmZ-G9Q(p(҇vyS}VA ٽxlquGm4з VIpV3LZv֪ VK$L#w ]<L361 `9@I``O yZ%jG#]ώ`7N6& +W*Q8=%[%v&rc#|  A K+ QE5,sR P⎣niKɤ/-RYu_pg㘏gE, T=ikY$קPηL lK  f߷BsNcir7r%DA i[ɂ\J')RiqL#06ZЅ@ dƗ~1$vNX`Ɛ%A͙=Kp!|jkc,@gL!6wzFL~jAHts0!00u#Cv YAX<`+O~sZ|smVJh162\Hz9x``>C4LkV1m:@󍉼{4^/c&!P@Gm4ǂZ3cꍮHsvT]p +-ч Z {O#B0r4su  mLnTSfnOV雋o.ڪkb"0Cx 7olk޻ A 2 Imr5  ZiGd/tE@QXc;og#ü6e.M^o LCsL# _/X=e ԋ*9rXN5zw&T.!hGuMtdnk@Tcjc.,a*W˅0YDEtbmVevۖR+o5&l)PX1jlCwyY,'E-[ ҳԶjl``iM\]ܢi [z%xvXҊJMڏ v0U<фF*Ϝ%jG篵$ہ$h `;D 2@ XE;A <䆾{uuh6m9Úv._Z*&|7ɹLo8s[1?r6Ud-^TS6@=< fP"ꑞp/KZk'V/VVi/,J~sAWY剜_B>lzR$v ;5N?(v 53x.s8eC͘kx5CQʟ1-e/L$4[Bմ1DYBM~^גaW_WMxR'>ux} ?d i};%2g)g7Z=8tҎ#񅭪O)tp~!Mw[iYLcXD_wFE^It% PX,F +[# dVЃl(ƴj۟ruڎ B _QV6&6_6Tŭc,cn՛ݜ8ͻ1tJ,z-]÷g _n\͸ usCazB(#Ft43A_}[ӻޕwѾS2 yLdtvZFMu]p1at8ir%du&f)VLpݦvGhAS>"$k)—éd\;bJĄ oLr}8L;a3bv) ~5#X{#{@]b L>Fxq̤ӋPG5>O臫mM+Roa ԯ+)hY>-tT] َnWӺ#EWpwA(s@teh*{ ^',˘"!k@>z?ro"N1|W݅e!ߺq7{xzPCSWN{9e~= Ua;C0ŠG[:jZ\,xvl X-[T ȴ,1 cOA_iO3o<+j UAFږᄏ>_b<=#ɴ3_mc?#NGbzSn \ ;$ 1mݾ% BwLZcǮ_^@t4||->9b;LYr#'\ l1@p+?r<yzbJ h,>j'?KY +Ox:K'ȍy&>)pe!:5>O=H {%e4Ls0>wܐ?OusjZguB=AVy;msRxGiepBC>]R)lD2eT᫆v9χVR0X]~2esyN=Zw'@.E]_bPU/379fS暊i5J_ISg4RX؊U-u=ܒ$++ڤ$HoH o<4'8HR |ł9hsr<4qR (|,m1Z@HO6)|Kp89lTd P&.3$D|q }L+N]Dˋ뤦Y5uY Ls`s݀u2WW\l}05VHQ!;PxjV[BeE}T$vbA![ܾ:Q(Xu)DKϗ?Lga tejv(7 Ա ff;ڌSI: K2P\&!SbAbRSa4m\qH o+ Dd5[R(2Z[HW@tfy&{Ɣ|w,_m8W8@ YSD'{_Zj ghZ;:ӳ>12w$Z*3?X6 qwEjJ;l"If3cnD{w#N}<7$_<ﭘB}eӊQnhټqDN[6qO'P:Ȯ~o|aUQ`PLG؇6 @A^4nqq"Fݸ{B)cU;Yא0{jC{!jm ZzI˳ ;X ;jz l]Z#̮DFD_Qӎ`qs) R1}oW3l+ i!w#*9BNgCО]8i tHOݥy1N&ycyx;K5i~VWڸILB1ETıT*Y7R`>W>ōPb,77WMyx]XV[mDL춑dV8d 5 5j4h{Nȫ `ƀXϦmkZN[)yK˘;fDnO=hy`W"Bf( -o5~^ 93<$OyXǵ[#01߭`ax]*8-'Mh"7UE3ǥ2h_g/x K -ȟa0sr%\2b-Ue6 ae)Ky4Jԡџ̳.~yepxFZ%ˉ2M_uG]1<&?;B8fe:9ve|xw3fei%%!c# Z\k3qn7dʻ)!ﻅ<< p3YP4z"nsfI/;Ɏw!S=orzAqt$έ匣U(u8pEܝ1ST8ۦ>8Ƅ5'8JEm=3_Lv}"Z=ys~or;xf%nJ)ټűj1[Ngw&i>P.rQC 6)!kR**,}Śƻ*?X^ȷK>]Q f~Bm^NeYC 9 ^`S$+y=N~if >$ܴ%9`!?|}?.\~| BxG]/yiwxn' Lr02""\Y28C/99oڣ-;aCa ]  zXwyfN8/V-CڄEs.W?F]Ut8Bu8>` pTߘ x5wJE'bP!gMc+~# Exߑuo>X-9JYOW|>NX +n޻ӌrҭz/h<_y5zPDnm`6n:f{Kb=]mvXKJ#<QʛH7}v)*rl |ڹfI޽0mG {2v1g\?M|N 9Re*9+3,cZ sp瘫d ʋ/2Q?(hb?~[͹jO?PK!S2Fisort/parse.pyr񮯘6Ų67&ܔˏĕICb r(aM\tAˮTRHgzz=%I򊯋7lMQ޲\EU6lgES-[W);Z!jAIj˖f]5_*q]@UF$moӢtyx,b׋zo8b/ST4*nG 7#FbOy]xz&}&5m|)jekp Nz,W|We xoϿe~k 𶵉y͋~՛U.nΊFclw ec؋3})|qS}ͦ$%lICҴu^޵Ʉx=%HD3wӊuFPѩF.L7.l1@[ azBEbʶh8HVu' fŏ)66˄%pz 7(ox) & .zoq":OŐJ#Xb0W Q ]7(RkJq c!#Zj Vfs Q'v$)qIcS$&i:l2D] OKB?g6èciɺn XȝO0Wn+#:s횶ukf1ѰT=`^F]< ,%悧QښE&G4i>;q `e? \ UUr8"Ϻm>]vk*-K`Bh23*0r[4eNN`_yssUf|.`(F_| j+(EϒkLOF`؜ΨJ xm65}H{(9co 08+/UQIL;{ЗR8 ×$ePwF\Zs?O"Fć:BPFf+7yppKdrv[|RۛjhIGx&_~G&Q$J:&{4b")U2Xɹc#zA܁aOwjmxI8$QX)h l.dp6q#5l$!)HAY8*oGH<>3u{}~~~D`.`hk%$" 75?8lhl%F14s7HFBM5++`. kW{~N60A1h6iϘ#^ =5wi~\R}+A$ 1K&ܠF#;.ͳsb Ì)7MΤtU, 0o AEZ=tS-2t{I85ʩܬmLA@l|ڡQ/Dlw[Z4?C&9,2Ŏfl'<a~AИrEG2<1= hB>w.6GX'OϑCBD-.Jʧ|Ќ?=ol아@e2[sETLGFHe*%%oJ gf\pO?ʪ¥~8 Zg]BdXbRF1(&xLlLNǶxE'SIR#=L ǞU"WU</dQ@.KR/LU ORԉ1\e:ucǾ:5spf8ZTe{,Vho`h7΁r%#2QI%䖉={89'Y{B4mY&`~7\ ֒ŦΠK%a.na/M y*f,lHg"*%P։OT L#E":FE)[3%NJz u/L UJ˪4C0UFA.70ɼY٘S+=Rc`h /R7dZ `؄ӢS< 5^Xa'T)8'7hhy%Q\",Mjy^HPX /#YuLH2Hv[N-K :8 }%]&ib=aoD|  .qJ-$yxwt4>Ri<39Jc(Kj}ÔTA c!k:މ]j(e 6HvkS[($_1}r`;MAW)B(؎( o04f}ѱ}wk`26)?OT>  i0nrQ'A]98ֵa<ʯ]Eݩu* fgu C^}2J%ʱ{ +kuް wor!w^Dr|nGw"uX6sRP\Q9 Y W"؏/' !d? 5_>BGok)_Z |k)a8ucH5vU7A 7$βТvϘBQW/3yÆC$D|#%.yKc]Tv&D5q\M%jbk.X2jg}xHK?)NfyªRg[rRuL`OԢ'&q s:+r?BQ p>;ĜŹbW#Cr&*p3 .񸸫vdW >y}Suzo0m&Z/8Nsx9 ?|b .x5jɒn7ҍ&RJ>֋}.z\ Pb*s6̜gx;Om=ŚjYVy5r\evY8d:;PCZm|&]#/HRوueLq^-l!DEʼxib,}昱D>bb;957מ0ӿZc3QDt֭8|ޟc!t~LWWOE]k U =v\F a)ʆm:Fy zR/y\'fi!x!» o ̠lڞ;,|20{pU)uEK}=7vom@x[_O'} WFjZe|Cvܢ?x}`ez}=cI6Ca*/ՍxS)įV  ۑ#vH u\Nr^Dx$6?:'bzd7E*l÷ն} [iG6,~w3Ca]&ĸ] LyOɅ%al91XxBJi1HP9,N0v{+iI(9>`b-Hد7,,wz{ys}K%Ls? TOjmK2u\q.O_841 ; ӂYiBX>ק>t4`5Z6PK!x' isort/place.pyVmO8ʩRҦו8 B[',xw}xv(ر',j ɼ=3IHakV"E91BF5"m-A?0*H0)$I&^dĖrc><ڄ JLyA6>~ ƅIBgr;WN?l`BQ5|yQ=C#c3wspp{J;tZG~Jlp4$'GczPw*LS1_\]^ouC0$c&MpxGVU2VVLxV[0淈LQLE{}{u`s]PK!isort/profiles.pyTn0+R@)E='V%$&I+8BNė>r8"N5y+ I^5@6w GeEBu!aFNWEȾf?TUh>obӬQ MW ;߲Ou)^*DK%93U'v^:2nd G!@8=&]O쪗\xBc{A|s1.j0~5Wu.}5X;PiNpǹ\ Jr@VּQÓj@׌x. =1(>ʤ|HFF~DQClVsDчUD;Үu<*@5IqFoXQE9\e -W|s/p0"⤩&Mn1 WQ =K(**q߰3k=)Kܕ}j8 zeL acŢm;9|=y+3鋺bjf۔}V$JIOP2,,ړt-Wyg2[g^us)?,8q^(iͻ?{%l#F4-;=5p}E*]x{~u}syru ǫ3󿃜~<:19͚tS?'(>O6PH凫盳kiSxYzeg7GBpƒ$ZGEݧIQc`M]-WȲu_xpZg՛A7?ꁙF7v3-`-hA+u[Ԁ zu&V/h5p@Uѓ+?Nޝ7'W?%!>kWOZޔقO#(& yJYdUݫw4Jxx!%d\)E5;0@L zz pۘ`}U~&U}Z  4W'WH ! wT?)CaNjgҚq &z_.i:i<#!5 Eiqզ߱mQh񅦷mDuJd%l")u/dgmY i[YANlvՆ26Xǂ}  {Tx4&p ?p ؇?Kuꇡg3BwRPuWޣVO97T(s|zyăp]x 1oUYϟ -yj߿m7ȑ h2PP0c6+;aEҦ`R)D0S(Vu*yAfP`p-럁̜3&b ߚמG18.3Lev96HI`-6t=$9X˪eԡhAZiUT92mQ/؟hBҦ`0@/ #ME>Y1jۓ2<;s[??4+O[@ہt1FS8n$]k) %L@.?e9*QU[{ y4KP, Y#^y*2Ο0MG(X4 H-HB{' ߂!rvqHO,(Z{ZX!x 7yh)V82u (ҴaXӎHKCz q,h 8pik8F״ ]A^b%i0u ,,d@xg=fsd^G/M= w/)nusx2z /gx\yg-?kۺe5T:{8n`y"KK'2.:Elv/K,U`nYe}E- P3t])m\ ,#[jj%)D>V )jj4)&CBCI"雵!сd% q"FR)c3xua5NVpf  ;}H=bYgtZGӊL&4^ܜ_/>gm7iT[OJ拚$A4 $(v9 JYGV2{E] n Ę!Q]i(JdQ7i<lΜS[3vF(MLTF\fu8DiNDK 1mTCTI ^99 .ֳTp?/s"Yn)3ˏFB4WJhj1iIqb@p|jlp2OOqy3h7"QG(xwGbk`6,+tUnYS$کX'ߚw$nUо99o=D=/;p]6 ڏc_<#"ʴ'W<v ,XaFv ɟyŮbU170X.G6 HOtv/X~22gi(ٙtJySYB4(/;k Aw3! ))z\]~YBbpdbwu56dz=[g,<0`/]MyaT8 cG1Hbθ8lypit ڣ;e8vT乀#q/lЬ;ŇCq3'${B009#$L`lrsL-`Ѝذ1]]~ b?!sqaF3C IMufp54PFL~qΠ)ӗ@ Z֨glj vEftwR,nX腞PCoN\i;>w2wό5Q#|mt$.MTMde^>+Ŷ_5RQV!7*c;1dEU:*ء:Mr-2loU4sVC ض}EtD<"w#NG@*T@;H$w$G3+|(VZ3~ie+xIBJ]S8+5q.N9v@ .3Q~4ob[؈eQY.o? k. }\gV޾bY!4Z7 a)rhʇmA$w:֭hbu gdh؎;Kdx*M<"|Gŵ}9i@(VǡPQ.6y¹0/3jv|qS8qm2>~;Ogq@S`P!sTXce{7q1z,8GW*a|LMɋ(-B.J}Ӗ'{1D0F{`\ņ:1!(H/APfC)[Vzs$Z&aIXd˘H[5s 鷓%TM7N8hy1-J ?vc8Z ou%6h1%s AR^Bc2V`!j}Aح̝^@aO? BIcR4n$0pc[@#D°g(d]ZEQE+ +;w+[,Bx4SP8aG4*493ߙ VDREM9Tؤ%TXӯ2d@(q9t/a*M$A_Z._u/W%a&aWyFVn:WBtaJT_gR\+{ZLy ɍ]LF,5x5V'C dƭEl(Y1sooݵ'P(Qٙz5<;]Fo3@OA6۲_?bFg=N/>Yw(a8* 8:窮qm{yǽYGov GH+ӏ}׶Y7Sc0bLhx#I(WG6՛ S穂ͮh1|ZC]mN%3Yͱz HxwŎC 5mQ>^w}缀b'l6|͖P7nrKl}:6y r('.S p/|FmuEy@ZMS (ԫ?PK!Kisort/setuptools_commands.pyUmO0_q2BKX`JLB@i8l}g)i%C=wB*i&R+]i/Q2S\lj<2#2LQ#65*hQ2SFL{5:labLbrp}??\]zeTk3T7l#/o5PjâFBT"UxX4DK4H3Sh˸̘[[LG#ȏR+h-$\ǀat z$3dZ rirdIF V Ѡiy anٝ\.if}0 Wy:ғ`4zHl[v|6,C9Nl;vN耦,P"IHF}vױ7Cc<(7A]aczR|2s'QvPѵvwF6:ȳ"v!vB3͆,Sfdc̪UCq,skiʐoɅoW# 6iRUmo1, ]Εs;.`;NiN G'xXaB)Lj`v1sA(}?mauyt ?LݣR鐽p[#PK!XFv} isort/sorting.pyUak0_!̴ 60#- c}MS8rUt Y$˖Ӥ-%{:=M%%Vbw-kLZ 6%,wnl-W MHS$)RpJ.Vf@ZmZ.XJ/Vc3Bqކ|_{S B^XC6j|b4!}ՆX=uXt\.;SRV0RiV֕aǶ Q(h4-CIȇPxf};cA"7i~iL>$+xjP=V3ӆZ4 -ilV\vjۚ4I1լ/BXS5NcPN}*4r+al]`rAnUA(7fϟbcfLqb+NT+Rz_4LG{JŸ 4xiCxQiw>|lAh/|RA/DXYPpٞsr唏c>߀ۓ-}zxw~ I^=Sj+-W7*Ri[htnN/yCDot07'$n]rH|$qIxzŅ'R\KKUII-.2tybPBw ƴF1? 3&`8wcbXJ  DT <=l}6}j_.N^k_ No㮕+k6$ sc9:!jYz!/3 FOBfAc""-R~)aIub^2!1~RybDIp3gq eh'e!ZM.Թ'y^ʄo^҉:r X?fV 69 ^rСnkf9IBXh|`cφ!`i!ab鸀06톒D t{Z'z#H4 ST. QR9 X珞H0~8&>Y>]q:c*3RAqe1vR+7+_f)&KszeG,'YPô< IGɷv&\$2O["PQ%0ئ|\8jAb W E5PA"cmY|jB-$'egdB2*@XN5P #{P$,=U 7` h;Bhxx@ztBP%Ҵ+s>tncS3%niGxi=LUYن1rxOZ+B[ 錔S6NPwJ ~Ȗ_džְX2yan JFsIFyR0a2'$?{ܑ(c9f'½ls3Q-4U8_ 5AE^zN19, XT!<4 `v\rZ[绹GNṇ~[nrR!ZЋ?4Y:(wUI|D6WEʒ#G<;W_ Y;0{;qnrzb~X Io8#<||4?@(p(fgcvbpbŤ 4lr?Ԑ]݁s*Erq#\HY o)^2`LfНcP3~YFT:c\ LU\Ql_!9x׾ d'n$9-U)ȥLyjkͅœ3<+췊Rm|{ x7TVZWK-Wo,E"MveqͺF%y{4^ţ8)sƆճw%PEKSR1øf@6@G~@zùcUSdRS A09:J;=z{0jlxZA)M_tc4vn_6`Bq\IUnhnQz;ְ35 8% wHT5NԾـgtQ,{ C@gTz{t-)RPƫw5qȜ/Qo'45t~6a4 57 g>ЃxYqhS qovsZ 7Qj'!{\-W('o'f'Vig e4)1~x%⌊&1Ta/P9-+¢8Xo b1*&."`U'-S<]kl3V- PK!{# isort/stdlibs/py36.pym;6 =W8w̸]P$$1˗At@^/M>HxGL0Z'`JpgtOu2ry>O_7WV&7Է:Rf>豬?6NOcl|yb/weӷ0r޿{w?gt1.*vPF tRq/|3zŠ kԏGήÇ_,b, o˞8@ou G(hD6U ;ďZb fTS@BF{ؽ)[aĽnED) >Y,";BFA1zM(5dew:Ŧ!b\Hmd#A|nciC[ ' X*2٬qtu7tX/Ԍ_Q<ժXWbjwGS-W7ufɱ2z5ţ!zr+yНavzR i pY&ũ2G&Ψ:``2C(EaoӲ",fz-b-r̭, _uMrEq˿PK!S@* isort/stdlibs/py37.pym;6 =WؙJdM EA|.{ @I‡IO>==~_2@+ \NC #:܆26ZK>=|:}:/ߟ// 2\YhhkqF>LB^~l΍&^ܞ64 <ï_O/SOi{>+F/bUƥ:lnhGu[ЏJ]FCv͇`xR/{=D }|("^IkghU?2}%F67l>f8U6Ũ;"d29CF%Ni.feEU :)49r>vT$ޘ$"\k lB3"u Qhx! ggSE5TUt1 z$.)wgIȧj1ž9sxɓ 3s`j<1"Se-lX VVs $'Ǯ$9uB%]-hSKՖ&T`g+!a*>R;J.ƲҲo=dz5XnVMk!¡|R2#!O.I2T,c@(ZD9Ʃ?RTC/ek? mh?[;"˵eo^G#9kŠB MjIWɳwi86nXxAB1Esrk{*W4(wkؙY}yZ"DSw*mx6>-,"]NMZLhşęuk5)AܮIϔ] :);Uvt>סj[K4DnT1$7 Je)TȵoILAKN}N\Q{fỬ6:shH! JtG? Z,F'i$W=ٵN:FU a}M\aVG,W!ocm fm~"VOqW!y}˿OPK!{'% isort/stdlibs/py38.pym;6 =WؙLtNf.P$1ׁ2d+|Xa% 40m(m/ϧ_}y2"@0!ÕՍat-hnC*=]?:u2Zyûn"Ye\6F*n/pPXP!O5'i1d|W)5C$LJa9. %x|HV/X7KzI_bdsCXmSe3]ɾ#B&=Dht^ŸnVFXqz@H[ݠB#kGPHiL"ɵ0)4#RUQ#Ob,{+-ɞCi,7UElm 3P/)ue'MԂqKji*0f dYd \A@ *ӡzǾbڸkgubTO׼`t27{Njv{Z1h9Py$ZAUn/mY5>ꃍ;^;tP(|J+`ٞJGvF{8vzޝ&F[!^@)mO KvH%s'!Zg#qf]ZF>E!pP2kjd9}FhJNn4ݸu 5Ulg>ЃxYv9oh3 rozSҵ#s W^ig.;\<*go'F iQG h8Uc|ag"뀎xwd4lWeqwFkek[Y~ltҲUcEq?PK!' isort/stdlibs/py39.pymO6 F;Àv{!KE(*߰>iHzXN1DϘ`% 0 )p4|h)y˷Ꮟ _gh7dЖSF>So1?6X//n/uXtfOi;-:=Ѝ^8su@&H-Gu{ԏ{'QĘ]1^˞c8oex ׅhDE`u(} `e,%}I͍%R^+RRM2!BcG?+Yaĭ*"mtg G'׎*7¸>N4kClFN1xM;X]mS,p!4UPcUE1K~N'R I8L/~c] 2烗 2 1UsgO=gh8*{XTd]]3dq~3Z$9"qJZ$f5"V^2/ J|P_$ S٫]i9aVݢwUۢ l{)(u5J ڢqڮ++eX<P"\r>d1sm:*LN_~t g?[c/Bũy/vh/$eRbԮY%1֛$VݾǪiTlܚڡBßd\I'>lUhnP:z;ְ35 س9/\D 6HT41 JIGl[l|Z3Dh,Lh_ęuk5AܮI]:)Uvt>Cdu,QS u3( =e6S ׾&Zt =vX>ţ!r|+yatrPOZ,FG)*W=C:&UaWn}Nܜ aRG,7o1'ocnmf=ZexǶՐ~i,=*딎(.@MbjOh:Zl,A@** ,ѶjZ2?ۗT8s3vSsAdkyӫ-Gj_g|;f+ em۫I#x(EQ*+]*iL`$*AiFұG'FG2ŁcYL(ǻĆL6Cۿ߭G?%4lf@Ӈ n\frtUvX˝rfv]I_+vĪH[ j}S:PK!Bhx isort/wrap.pyWn6}Wi>$H6ͶI (6ЭI`;ËHJm@ glꖑEݼyRo%aoM^={w,"7 *+"gCrQ@S_O]ߥg7W9U,_ڬIzI{`WuT]m1F5ҎpyK*1ZҊw[6#p u3=pQ)(m6cuqA?TB@gs (J`yʡ k6`Ӏ7F^H%3~[6m cD!WC%R[SҴ|H(("t#sIJG,!^|DG 9GzU/k3[k92TmI&81z &?EV|Y £47dmD}2Ҧ5\ٻb)kST̒]\R}esUz[˗_{ʊ Roikˡ̢ǰZ]xU^nJu!ώO5:-:^\їtXLO +6$Y4]K .4 djR6rb 'rtд4{7={pw:\vZ{z?}Z?jX&jO2Cj5C5 q#['I*hx$ Iԑ. z 8=Mk"_T 2d.*hI7QsVTba`wM^!4O3B>HgD]m_rT0kY2g|qGdt!@L K5W@͏~h_I_n'&ƴ[d D¹KSv4k "!SaK_RGf6sחq*l\;V18.Q-2{{#{#}'66 k)~v[DVZCWlGWwXqD~sFPtY͍$T@?AGwWic$:n fxUDxr?_ƅ|=fMǹ+״=G h.B5qɟFXU4J;$u!%Js ~hcHB>uh - \1(r͖%"+ SBJR.rBH ,)v5Ow%yV<$TUqIQvz |VbEUrݎ%"ip )E.x#c@ %aF![T௨ܻqfƇWo|FKd6p&a^jn҄r׽(_-CӀJB÷)*Wd"P߆Ga% P'kbLJɟݚx-7H ϐ٤NB=F1K6b;U#U,rJ ㈿oU\+73JxRh^ѩE [lR&PGcֆ=d%4Q`66cU~/Ad: jȟǒ v"Y ʙJha LD(2dQz2REe4 P#SZT\eAT7υ-L$Eɸ)vŠnmhsë-q|ր\-gU̽ K\8M4^Uʄ}AYG%=ɪqSHG^r"&e9H,L@zlXk3 熀VҵU<W|Mp;mxvdyG3ۥ,ū˥n]ZBGW/l U՘bM (aom czy0$DFJBmFƍvd`/HT(jRI @[w8gReE؛>F@~—"=1q M>wɼݼv[oaw'dV5E@,V:LL ; `yC|hF׌ l5us [-CI2PIp[..n8B8j vJfMBۛp9+o/À[lb=yNwKv[u3K`9uj п_8:ݺ];]wcQ#=lrm@7ȏ2w۰3!hSPn"7>bM?wN9:8*04ns-`gBj%}e[HxsGyB {ܳj oeUQۮ]>Ȼ }}5]ݑRj9S t< Qn(;l8O$i.O}T6F;6&pjcGLK3.SNEvĒt^{>Vgdc;֭N8+ZmLkBרnSg&uОÖU @,vaQ`y MjK#[{1FA?i13JQ(=mb:AjA cޣ:Iuaxh'mǞ4㛧KmL8H%M|լSN&O(_MfXgԽe=vThSjۈ6t*;?y/~$}x\iK-6k Nc4=t:? 8]}etSd>,r`gvx_/f퇽s:;\-bV&W?~utIuG?uǓhg{QDe_Oی $)ׯN+O`_Wy35pT1̧_maPK!H^&isort-5.0.0.dist-info/entry_points.txtN+I/N.,(),/*zyV +:%$3X/9?771/Z` "SPWZ ̱+PK!}BsAisort-5.0.0.dist-info/LICENSE]RKo0Wrj%}XK02N9pWGl3$mՕмnjMga- 䮱C#c?_Gw"<4` =MC Cov<hW8ma6pcpd; /h:߸tC#\ov.{HYqlD2xf7F|pFw$&"C]$ >F#v?[(KNfה-L`6*fERF[pwd@?~(N@بx|M܇K5:ΡXo<1NkOO ߵσ Fd`rhїaU.|uZ#Wɗ!a0~$00Üd2)8 d1LO|W낻Gso!ᖞFHx j*7gE?w.|J?s~~C?姶?͏oOoa<Ǟ=̘+(|1˵ ei35g`n?RnʿmܳVKQg M19S.z > , rI+8G-Al#v}?p Ml \L{4/dKp(d@ d^KMb:M~LݺA+m&Ot3ْ.&,;p'5D5?`Dx̓E-PPN:GeN.ergQH] /.b8ٌ'xP|3LAIzQxEes R: r[a3^lWj῿u<`+LD4*34O-Epւ L t8@$%OS]@(0se( 7hIEMrdtT"Լug$hǁ!WP fe,%;C,> uIWzy]@8To-lZAi!^Bד (SOD&ЋLiV$'ij@(+o!?BV"xe׌",J)a%hF\p%EFx 6`pPh =*!(^>G.6N_G8c3 KITS&U͢34"7v'gMƺ9\oB왳4ZY?~yeM(4( v ʙtf a@j-?b gjT?#Mg!U<.M:@*)1VT 6;wcV?ȉ*0Crlnʀ z4F,88qWzI|/, (YbKR hUHB{37?O@uz|pw/{Pn`/s1V@W#|jȠA)ty_~/r{0QR(# H8(7C\ߎĊڌ?GRJdK $N%} Kƴ:pRqF/sRmJb:T!fd:#˺0K9zutrza_|i7f0z{|×'[WxuK5ʼnK0tĐsEU*%#C&`BDdEP;!USU5 L(T-=+\G}A`. _jRY٠PٺڎO]"LyKzn<:ԩ4?Q^jHϑ!#j<)&SѾqOb`r_90ZwCWnUp>`Lp4z9:v=p4-xy[:T$#WV1'L#Xp z=WȻ4]3:G2SpX. AzXg^";`QsO( X@V@ѧ5Ȱ}iͯ.D w:[.ªA1q29(sUXP\D0ɓIM$6I<ن acfwo~{o?vwa;7׎s>lyh%\ql1ii+Y |BS듡I 28!My]FDUNoVX}7wmJj1 ̇qסGx"(Qnp" 6MpJaz_gSPEPiGҾur؋ʭHc҉P+)}{nd 5370 J*k8Kmʃm,)kGMl'@R׋Ҧh(aA)F@QN㨩HhaAO,#zIMu |3A, íGtsA!A$~xBΒkqn ط[Iv`; Cy}(+0-^Q:zXF4'JfD30=^35$L_'Y{`|yQ^_  ƼL0PPQuC `*L8? eFasFV9;8;MB0xя aJq 9Q|24fS3jy7`Fk%C1~=>\>tAInXj2r/|(x7G'He&~>$7()Dž6Tz=BW$C$ nĿyavvqONUWVzڜ9A_ R+٩f3Ԁ//@-k2kɊR69!/+k,' hMQBKvCK T,~]!:wN֩͌OY9ꦐB 52U%UUe t̗G|o0`5wKD8#V f!nfK {Zbo`=ot ćz5#9[`ʎ &50,kQO-7eWŀF7y+(+IwKuZվ;G_+_0AXv=oEd}" 32$kI_7x^U 4q0`k;(݄HI:9ez:F4NK>d3J(A EodsS&}6e{D:.^L_ e;cnaK wZtDnQ ܋Jfm^Z݁(~MoL52VZ} )<~6)d,{XD|ٔ\dJ̣M̹[#2Skօ`*bHf}«ʺzR 0Zbv{WTl-LO65%=a(kBc$s'F@`_MMA-ͦ"A0{ڊ0e)țMj%8/OO@/,mJǓ<.L>aD?cRCj/1=WoD9ci|@sԑIr8Ǟ0IJlW"QBsNԀZ5F0'WxA+V\}_l~bovCi&ZѶCgE@:&Ei9 :lk/X*xu3/dБYQ8s#}(!gqMt宣1|¯8LP"2هjv&d&T}p=DH =&a0*4I/ #ij3}3Js"4N oJ|{9y֑396J]@aNMܓ˚! NJYgL*YYr-ޙ^eg&ŭ\;wF0eA^]*'eI@XGQ\ _%^ 8W= ysɗ"02־u6'8 ''.豏@D&dAͽޠ#D?[9gEnsw7{kZgKL#6k|tŧq 4]~-4^P?|؄l x; @Zc9r,Uq?`[uo K:K@ h/@tFp = #8Vi{y /PK!Hcfisort-5.0.0.dist-info/RECORDuDzH}? tb8 F fC5QCW Eͧß礊h)V`C'3=)I췖Ne޶.OgA| {gr_8WâT\i4pA>-ߟ5P!qzy<4 b=6k=>"MZ:p4S L)p(o\}\d-#7@R&LAJ䟩Qbg% .<ѹxܢZ꾳<Fp{ : Qa 7IʴƽI$$,NE{ݕcBCp2hLi$ar)J"Ip gz )A7l |g%J2 yј. &{v5MnKo716zpb/ґ!Ei;`6D4bbН+vŁ wv,0LREVZaJ‘Ha{Rⶮf:oUߏZѬR"pS#ALqulSNvCӞ7#yJJdo!XR퀸̥Nv3 @ٗX$7rLmq9x_Y1>B7-Dwv[EB)nџVث// mmjh:i91[ =䛵x&ehe ;_gmoc9퉂A4ð]J2PKtvJ;?=!92ϨpUA2DJ\-Qd56S IOfG%ށuRȫM|'ӯi/$R 1^H`1HMJ^U j1IfzN'ɘS߂07 =oҵu1ڄJ-6y5D qD~ ŏZrY8bMaBaK׌uHfo|~,8h'.6Hzt TQ^2}g ]l6 7Sp ^~eSTǹX rR>XYWfoRF#"k(I첩:RY4S~F@kQ U WrREOYDԮo&Oʹ֍5s橨hqje[qQJUg:&@ eb_*Dk |$gZEaUpz!Xu*3ә]\Y"8y#[Ҳ6y> a yͣݯӰ][.MJY)urtp _:_·)O*BA[^l]hD5q}9RPO:?(W;BUJGPK\Íٱp{U PDU/V?R[D5NSJ*gWǵӥqO<_PK!ßgisort/__init__.pyPK!ڞC $isort/__main__.pyPK!KXzSF%isort/_future/__init__.pyPK!W0"isort/_future/_dataclasses.pyPK!R^3isort/_vendored/toml/LICENSEPK!RE 6isort/_vendored/toml/__init__.pyPK!e QV7isort/_vendored/toml/decoder.pyPK!@kt{ %Wisort/_vendored/toml/encoder.pyPK!NNgbisort/_vendored/toml/ordered.pyPK!Oj-cisort/_vendored/toml/tz.pyPK!\disort/_version.pyPK!Tϲd] disort/api.pyPK!՝1visort/comments.pyPK!wisort/deprecated/__init__.pyPK!][ h81xisort/deprecated/finders.pyPK!kbT~y^isort/exceptions.pyPK!G57 isort/format.pyPK!E^Misort/hooks.pyPK!7v8 isort/io.pyPK! isort/logo.pyPK!a3] isort/main.pyPK!h1SWisort/output.pyPK!S2Fisort/parse.pyPK!x' isort/place.pyPK!misort/profiles.pyPK!0ܧisort/pylama_isort.pyPK!?)tisort/sections.pyPK!vE_NTisort/settings.pyPK!Kisort/setuptools_commands.pyPK!XFv} Misort/sorting.pyPK!b+@isort/stdlibs/__init__.pyPK!:+9Sisort/stdlibs/all.pyPK!hy#)isort/stdlibs/py2.pyPK!=]isort/stdlibs/py27.pyPK!xГ7eisort/stdlibs/py3.pyPK!EO Bisort/stdlibs/py35.pyPK!{# isort/stdlibs/py36.pyPK!S@* isort/stdlibs/py37.pyPK!{'% Gisort/stdlibs/py38.pyPK!' isort/stdlibs/py39.pyPK!l isort/utils.pyPK!Bhx isort/wrap.pyPK!f0.isort/wrap_modes.pyPK!H^& isort-5.0.0.dist-info/entry_points.txtPK!}BsAisort-5.0.0.dist-info/LICENSEPK!HRSlisort-5.0.0.dist-info/WHEELPK!H$a?Lisort-5.0.0.dist-info/METADATAPK!Hcf:isort-5.0.0.dist-info/RECORDPK00 1Cisort-6.0.1/docs/quick_start/isort-5.0.1-py3-none-any.whl0000644000000000000000000024774613615410400017651 0ustar00PK!ßgisort/__init__.pyuI0 E=k5:ԢS> mJl+.dٓ@ xKHgJVRJ56{`$3>t8( 4gBG^Dӓy TvU߀9/s] q(^хnں7 %o7g7~tEjL*4ePK!ڞC $isort/__main__.pyK+U,/*MS-@l..PK!KXzSFisort/_future/__init__.py} 0D^%C_"4)"mRŽ,3fS#~Y%E''=e@K,6Bʬkik UVb-0\CnAOf Vph7tƝs«=9W'PK!W0"isort/_future/_dataclasses.py}kwǑw @ BU$9%XE;D 43 ﷞= -3w?eYYA\z?MUY̾ߵU߳EU4ɾ-Ne(j7oWlYWynϊ|{:W뇮.<4|[]ٸE-s=s7Uup7~{WϧU{pҹغ5YB+-L+M[Tej~ SZMa=( U[0fPŚ`86;^?߹eU/',|kv~ŕkf|ͲA?, ZouOW2}i0`]M C?yUlU` 3l Wm6N]@\ 8GY9ݶ,JDV47O;ώ/|3`of A?g_e%h$Pa siߡowqɕV__ 5=N{J{X5E·i~Pq6M9<ijz3{!Oz ~~mƄ{DLI`&_2|R5ESCȰ-&ѱN O(_P)@U$x,[/:&041$w:u| e ge]-S8Ѡ 'lN̽OVN_s5!DFZAᕓ/g%c6`^^C,Wd8ɀi.c81%8= "ImQBֹVʹ 3r a=ҿ쬒V n%d}!?O-cHP,=6b^(-t!N5rӁUF³aaK]o`1솚~Q2="$k*߄7Z cNY?G93 _V_2~] ?q'۳Qlg%q.qEPؖmyDr8 R8~({*f( /3h:NhY/fA'ݺҙ @u2,ٶ|A!h3 ˂YsRz&pWbmhNwP=h"5JSO@f,[ +?TRvjҝ4* Xyg rҨq@jݔ+K_--༇oQ? p@3_5PXh[s ߾-2Ò3Dzl u>?YxKBcni3DLx4`YP2xafGG8E#k7+" ~'/:R^-pO|4bd Z5vݫ'/sSRz}Ւ*vgJDO{)X 6:oS,̞ 5VXG8۳f!ҴMu_~oRh}+糓g_>aάvh+7ooGl OD?}2wn3S_&R*zrl;I5=VbBdrcR$@xV-0HqK5`CpWٹQnsb@Īp+]8?1`!Fs4hm->;X W~4eAXe+;„yDܩ6f.<ǃxgfU Fذ7n /h&,} `:&PZdžyDWX+`;&N-}-LHw qQ s0"+{Lg^B1}!C_,JmN ^GB [Bb&&z'ʕ#8(֛9t9jGZ z<ap73:,&|Ç\WAQH pHE xa*( yKGPI(9߮,Ȇ?cY#iJCcp dqaE-paZHNcTų 3e'lCVl㿤/F?YQ2Nнod"ږPCɽ}:2W\LA2Ώ=Rw΄OCk{)f3uM_!kNAWAl0^PV { ի" \;#dBrU7=$nkcI[AE%ZUsVh{-lxH$1Rמo'tV(z%-8j'-nIG? Iȅ)vg\TcƉf/cigN DlCu Œ#ӓod6:G z͙Y$Xmɸݢ 6Zf*7D~ Q#X7!oi w<'ƀ@ AkrIA74lK̖2)$6[:t>aSGE@!/N{04vf0|HjS4LގD*dɧ=eC31QD$&3B LY2D *"6+Q`+tgxulo5Cx5 -Q9]j rLl/[IyߤcLݝOJ=O~tD*@AL+~_C(ZDKO(]e&xbk&?s-[[=UDd#(YWM0&rBFk+gaɻƱb* [=)3>b裈Ǹ{'AurAM6Շ׎l=UVfdi1 $@iߦ;njgr/6KFfYW Eo(7$ł%vFX'yD\TeXyOѫ\Wa=ȕ{ O搬ѢЗulUk⟔˥M¥v'JϛuxJ>;9V 7qCG=@`[n9=FVd@ɂqF{'6,{3O "o'=D?*S-+std'P'ʆp3ёfNHf3Nq 0Yn^/t|ͦg G44Bo0@wZ[Eb_z)9F<9Eݴ $F{8o> >aD6|.=P[(- 7iQ_0ˍgjB*>BFZY2;;{$^?]].B3XP=EBwkS՛53':&)c[ufpF}stK{@޾Т4UAnA8AUV68O2ݽÔ>v`o1 ӏ-B֓zFXVOJj0juuĈ\Fҿ@>^7 SCyiؘl84QHk44~$~̇>ϢL3v0-axږd1|-Btf+>1@wTX)??S@߱qG[I+Ȼė\ck/++CGBvB{/*pr舏߱TO^I~6MQ\i$&+Jy~va^|5y<b4aGO?U3Zqz PdzGaP䨑:td#c rvp/d)0EÉ]dQY\Qi:|7ꑥzQ`/+RO='zrT5:. H=$9)Q49H~*;Yg+edуK*zLH`]9eUнżıN9*Jҋ MƋ'{VWQJC2eSJCfv_BPmRXX9Ec##S 90z7H@9|>c鷂IrK=[lEȝ*Z#ԙXی,%]eq/hl&xlNx`y]&_+ݰS34m\qХ42OLtC jσҰ_?mF!H+RF/H錹.4š.1|ҩ]BnPq4@ EڳTIj!4"ћ̇D6S8E5פgyn 0qc4uWqvۦ19`Q R=V6 ?< ̠gʈ=a'Yel""oQܕgj*pb!y|10i&|cD Væx:8 ;l bUQT>'`X-4_ ׭_܌}9d!'ܡy'.sXcu7ج sWp27_ܸ;EP\ ™׈yc?&&(@-~3wfi$`'%29Bs.#,XoDz'R- `dY 2,c=֖s"2D4ѻ }D!ՌRH !Dݣ7&T!0 6 ├[8 vxbʿ#x6W:VBʤc{dL+ 躊>:61>Nri &sTg],,?l$idהG&"PAbh$m·Q+nڞ&vDbՅ1_ _k1*wNO0K°؜eOy:  n"!qD e/ȯf 4C܇(ƛdZ_:B_חC.6,Y'>gonnp#D{ ]kY("!^Ѡ1܌WI: 87䈖 OCBB>}=~L/6xM.  t~}k"0<V-彃 e(gGhBNxcL&dXٵtoK F@ZD3@P"cR%7ʋ.g>z#HUi&Gb1"Z<[9!(fXP'ԓC("$;## H0(v Y EGQ!ŒC4\"yNO#:񳈼M =h<,jF!Gm0Q?=  Y )X:T)e/}FX:ى_|W ;L8ۇ$ol- J}{]LQ|!ͺg&5.1Jh,Tx*/m; jWGӷ@7mw7}Ap]Ãus/~DJ}fI*Gy(p"%s5@iD9Yݰauc ۠*_g+Z3D%qv҆*{msLhryzucÖ8 AL^(!@NjܫPAơѽh .^6,0`f[Q,[cJQ@g.Wqlrf0cxX8X:'&b[[O}d;9Jg039lTzkD-u]WٛGG>zۉaKP1Y@5 Tf6NeIMOn_G=fS|_O3Ub u}FްC͎~m|2/ )]Z,frrm3sI!K (=Hb;SX" O~ζ@=q٩LCax,ẍ́iӰ(,>C` f(F=.q;QtI$hV Ŏ]k8&*j6w֫}~bm5 xղ$`&W#:$,ro@ڐ(9"2'̳v2mWO'0B~g%RתeL s?1Ejn/]RݧL[;Lܘf!]0 aB d( wҧ/&2'ٌgf9죑;]4M 62-iFc|D񄮍PRC[=W7j+܊BM\:+aW[ ݃@tKY#EpCtɝQL{5c1~Qܺ scZy dp|<jN4VdOςͰ AZW1FQEXI)5yۑZomo3e(;hٙ9ci%\sysòg+3aKI H]>/K?@trs)@>[DDc<7&֍dY!{N3鲚oȨ & KQ2_L^Lq2wFxGTE`֖C0D1`6Jg<9qSQj;OjT(I6bTuAv5HJ$סNB .aN!"4-a6VIʝI`t wҘ6 +)ysNIۉ܆7D y$אe,C Z0 L{FP#3]IΪU ]/ON# X. C>FeN`ʦ6 j:J,0 5$bpoo  =_B뜅vQGr25U&nq7:^{Ya UBD-nkH^s?dW0R2״JqжbZ8Ի@4U=S@w\=riթ-'HtFOjk2)_]PԴ^58c^XNˆ+E! Dzs-L0Y1ozm^!oOuFӗd4*v=g$U 7Vhr7Ȋ>W$̑.X~Q£M6iON%+yt JE6?XTC7[Qq6A--xGggЎˏ h}AAI!/n8eSq>I"SXm>M/TDcnszx5<]7G7z~%C atuc̡c-j!J6Rvma}] 1 gأ}\үS̷ ݋pL '[xKߝMsuLkXEH9V62F|kҌCo0hK q(v{́o @ Kc?MbE &q-hAyNMm ͓C>|G Mqjy'TT/yw06ыs H%R|А'>Tl ^ ⏬_UޕH^L_g~JryeXzj{Ņ^s1cȨx=)‰DnQO8?XF!v<~;Q$#Dlba|muyGɩgǿmŌ i )&[8=>N j(~7-(%eG\~EOx]L%?`ʱ<˅&i[ߧDMg9r[+=/%ow4V(/.hrq@t3-Z?Dk7K{,yPyd1lߕ$]_t=vk~& cIC'<)i^G5A),ƞL,iDo@\<iy>cَGPzo#sAt)bż}ݩo&軈 `sSL]\ KbXGw)e'@P >]R r@NX%WM}'^tN=4]oק 8e3nM'7mhcOG-Ժ2LjWcaw?WZ>BeD= ug H^@qpVḍMen}|ut 0`e2h7=a>.` =&@'82 a4hhag&}zԃt(.3^%M}y=tF;f=Phc4ؖ02ucG텁'!:lƝϠ&#%gm"X=yn!'Zh(Rk'68x4Lpe/&P>8Z|gQX% |\J=K_Rvv0䵞Q@1vp -r%@P^.nxM[٬Mءx<@^<Y,2?+%Jʥ,f!;\Q_'CЦ"@IQZ C>l2MARF79WPmTU[bEE"+@c9Q1A[5*L2>ř Ms.,߉iDŨ+A)Ydc^0C7Ȁ+YB\g։s8Ъ"Ba!xXx|PK!RE isort/_vendored/toml/__init__.py}?k0"ҡcd4mhպbo_EqJA=$!qJ}-ooő"*IÛ$K*kbL=aߠ5HD 5u!HlDMm(61/m'6(9Aˢ1B^PĎ9ԩO#u@n|_y.o;;z /j%*Ufutp+)yީ޸jqkүRo PK!e Qisort/_vendored/toml/decoder.py=ks6+殆Z:ۓCg+TMnJfnV(s, IiI_?%;wǪP$nt7XmKyWt]qTwy>GK6QeU戟OnQj]Ѵe]jU'_'hz5om\$||T4yQn .zۮqkh.V9y{tt,V|Ytu7ͺ\Fazgw.BŘNJʶ.l3%&?m'0jnTf4/s ][>n+ڱEj%B ͷE'RG~u;Yi:4Qz"w5\/_4M\?z[-Qq]lAW?rׯb br]mX֤䫫Mr~<hxۖE3_oVQC%L^*4I`vY[W};N5XZLCj۪*'\29NLzMeErB5UY-tmBߓ I l*NVuswa茹%^ώGԗgng}Ycq_jfЇ&˻뛢MkRmE3N߀QI~߂Y.\ Axe(ep4ew3 :2DlO }WUG;ۂP5jE(ޖR:]+M=C0Lx7yG2jj$h4I}QshtMc[-`oʮ3tP8] k+@1f$(FU9յ#7H2i~lA s'0c,4Cƫ lpqݭrҚU &X`]]R£.2;}O+' Ncκ mtO$B2Y:#gӫ?NWĢ;;^٢&9SXX}'sºΗJ @CWsC]SހT0.0$;H8sh;jymq[Mtb MQi^)+Pw]o,%LPE{ ȼ'IV8 )Uu6` HɢBCS&o qܶʰ<%)cSl`<ĬCx!399I~ST p뾬~L٫kEg1U;HKJ k, 7eۡie?=t7Ϝ掷ndU,"^8e6֐âZُ򎽍ЩKy=Il:-!1GgeB,7GdF.j n #>PҢ-Z{BnjQ~a0>H~$K?U.Lg;y^yFa{kI Ba =OP|rDCHE]1Wg*J06..iX׮q|C!,1t\\uMP3.VrzfUjx6vPâƌzCOw vu u95 Nb,ʱ<8ؖN72󛾩KH 9fv<{FbXDؔ :~fFsU 5>hZ DrbdS_:W7I'-vL*6@QNϛ(gdL A:=`b'3ڈ7I.FyKbM~M.x.! 3-\ɻA^dP\!4UsqSdkYPed-'W_δ~qr+f((GWE&Q k';o[@1k1i ͽVd?qGժZ  d6ʎfSO|++Q;0u;hf 4iC4+ {6ij}]eԂjXt^Ws.lSY ЉaXl,)Zk*,G"(}UB $2a#_x1J4u88iZ.%q(D=}Ѭ=,ٕAUNB};Y}u+ZRsa_Ⱥ)&כ("1m5}ݬ'OS>jRġ4H€-ýQ%JOi*~tT+}7}e(!S,g.ON0v_uՄ,!~vfZ ӳӫ=8&֢ok&lz|gӳ |1.(|}pv'Nd{R"E{o6ۍ^wi`Z~tJ̾1t91z"xkpuG 8R\ 27rcͽ>Ø32|~> Vn^@< 7xQa|4Z@2@;MЁn< x_~/A@?;of&Bůۢ.r~KzLU'-ff4٠⁁I#n1hs 5XI3qrH(,QmRyY* G!ŀ|opVo氝StY `()Aozqجsy\,i5 z N6*VWn0q`xS~z@`o7 ah>]v'un-t?Ncy":n8q{ O߀"d0*)96>]8=]0a`L*(BQ;zT9I5jFS`zd<*%~(F]J?iDN>֖.ﶔD'/}Z'o u0™c(Ve9+3 ٘49rh&S%qg/~ Rt'Ҷ'a}? A_sTf>c;I `<!":ņy,uϧP`E6$̪cR <`= |1MH}lVY^N`Z)A.Sg#)aZdʔ*+|k_aݓq U`P䝐Lm0gxchINTT!K,gqOX/r/loeELd+)@;=Ld͕AH^=  K[vjA26H P1n򅎴&W CY78LET9 85'Jp*9=5|ס[hT|;}=r16,-96&kx=Ta<[t.e8X[{}+"]4U/Ķ(hKLxhg TvS[HzC#;8;|].'/(|YxDp@}FEP./v&(IQo_ZRlUp3u50hv;gھưv=AJT.øep?q`L+ g"1P4;& 8iO.d:Qwo{7|SǘrGx'INv^=SͿSw;s_)= C0LZ: -V0n\.8X/ Szh^4EN__P45~ꍾe CAB4-48pYAGBz4~s9?\VvԓRҤE:}ҡ6$2\},3&"xVPWe$ƒ nT0.i*z ٲB8NBu^ iFN%ZNy2"t/V!æ=5cz!>&'dd+ֿ5a`UسV M>2h4^%Be Nŝ+**<5j}(pREud.lHٞ[l\g'|p\>"*/GU7%E =kЬ"H)Ry3Ēl5ܥ8Lz܅kq9+ ȧP^DGn8q |01!>JϼW|4РJ8}jcա (]Tř,G} 8 ՘;w{x '``>6kӈK|M.yj,z*DeH%L}bsil"n*rPE+}xgϫ[79}_$+쿡>K=`Y!* '{t4_WP7ʹʅծA2S=<"CE_Ă(>ۉy|yC9V=e&-V ??x@c{0eGnpso}ʻPŢ >|9tKY_'ґxDyw?b_?S}MG*NF nZ^Eߕ0Dn‰j~}+/+E <! -R_;w@[ w^~ l71MLcc2Qqd=0* >z/V4hN8KZ[GGPK!@kt{ %isort/_vendored/toml/encoder.py]oF]bB$,1VwB hS @-WJ'fC2KR/%"m'v{fcPJU,y$׿UTW]~H fֿ?'z3]qE.EzU]={r)Kf—h9aiD؊UL&߳9qAW?I F hlXZZ R >!ȷ8K Y\"v0%Aj򲖊pY}5F6EƮ8+:T#]Kȱ8isqMdAEXт׍&i.ZLh'U)EF˒,Nս!h]ܗRD q%T@8dCyʴM+d-:ge( -RF3 "AX tІu韊 2+\7U}ҋ@dݥKѭy=Ŏ:n$[OrlN,x?=! RSUl<xu~~vD@bO&궧)H_r,&ze>۬6ZLm t6ڍo<`(-}Pjq,ìtgtP+@2] ȖleW[8KH'ɳPFڸ3E5+?@Az=c+br.M/ծ)Rz!&h,oXtX[~(m* 8~ |6 |țӅmߘBDKʞL^2 Lew 9O38Ōߕ)c}yj on꺬ϟ_Cmb ykzzE=ׂI[kϬn0I } pp 0p s}m%Y=:`Hh,P> Pҡa vyˏ6TSQM09Rkz24eR[cEʭ8Ƅ vl^4PpnF9%hɍ;TKGUCd%D6WZ_HbBzqMmXhmƪt3 + WZ !hݦi T7ZJYYfCcgmx )~w?o盳Cmz? aYDZ@:"t3ch\!Kyx~Dd~C:*C_fPtO5NCp4cw+N#zftڟt3i궬0 N%ĘA$>JQzz&'m6 > !iT pb+Y6o }X; HuG/@ZxLӶvkk1ᱎXՃ<ڊ)ӌ'_V8v/Dm92kO:H̫V('fONrjzӵ(_`d']CB}C. \#PaN\|mUx ^mKp_n GJ`C!4,j_/?x)ɳSZ#!RcA^=*RZr^Ek;]6}@ſ4Cwbbc[F?PK!NNisort/_vendored/toml/ordered.py !D-=8@K&tACG]Hfvfy.KD#!^RAwrfyS\/66 04 ,edSf6YvH䓯DppGU^{PD+n6Ĺ8G7PK!Ojisort/_vendored/toml/tz.pyj0 ~ Sac@N{QLhV(!qSd~;mCH h yr 5?plt '?}w㓣wglƂ\ ?Y1 dĝ$WS)'xU#f>=z>} dE\&!*qʮqųgbeJ03Gt+[048e-lgc4<Cw 8NS?&d@c ٔa"J \70`k ):Z S- 11@)ˮG gSˢ&hoY#vιW ]Jf+I!#WyůXd۬)7i#Uj jq$R(x r`?NѴy[R+PQ &#þ>Lo,Ŀk9AXZ6fSfAWk& vC[g3h@( ^䂂4?@|緽B+<>B;t 2<XJ~nT ߑ å{o'w b+b3;Y*0D8 Y I_69(`@_Olgm=|fӗF:#2gabTm/h?B#%\ R̈́ᔁD` D%Qd!(\Vd(B nEVy@MVc6<՟CzS-kw8> jzQݍ1E6bBҍlkBehL#{z=ؑ=ŘgnL0#/}○5{Y,TV6ԃʔPګj;_vQ6yt0D=SX~8thmv[od-uBhcHJ媖R|r#@eV{+ vh%%?*uuŖ @{QodCdFy/jf@!W6擅ُGggS}`Gu|e'%֢tLQG޽}b (j   ncd\kP3Sxcڑ+LC5+yyCصz2kשiX56TeTe{D%qFY'b?̯_iٴZ1v RFk>e,S~X\$=dN S+-ưNx@D7G§EVlC#ӆu[;SXj5Iǜ$B&&0?pP薨F9*13DZpG82V@zgզ0_Ua#!O  L Y?K"-8qKZة$=PR M_ݝFV e3թș1xbŶN{k,BwU򪴢*vnT)bl3:[QE\A㡨gpp8jRw#Ǟd5ex73^e$qg҄@õOZ7'l'ǚe|@[$x͐$,6H*!]WMWc1Q9&DyZ9!AX@1h4cѷ"l6c/DFhy(ݚPxr3Gkj?G2?5fdbҞR#mYNo5P)ݾ8?_^cgRoB7,_a`̾6bmdfBQЋx=TymAyBo!Oi~\)C`aӯsv,-J?P/`))wF"^htoam䡴o-+j_mc{iIjtp#u(Șw,iL!Ass}n |~ibaʏ8㳩E&uNS%ʲU=@hO;"[S/: jf+֨; 갰 5(3kʲCzrAZ"\|,xqPl|<D޿4V@o+w O%200DΕV]){?)U_[hӍ┬RwD)W jv%l]5 o.7Ր~.^˷-"X0baI&8 (H'S FgRcp\CisU4!6)nyMk6L ބ Ϗ7L c5xxW6;:1Vt'34;WN~7j{o3by~) kIiQi8ao~^k,D?g 6 vm߶̣8!+lڲYzZXF9;,GTGyX;T 2Um˥@%H }XGЀ$PkV` UA-`L䯃hV brNv@j5!3 Z`1_ 2х$URl/UNU>O;hxve ʈD%.R,R hcy:C^)1,㲞=PTSɪCѻ^ pEe/7Y e40}ы%}A iS{):9创DB[[Ϩ'ˁjrגa#.n"{UB HPK!isort/deprecated/__init__.pyPK!][ h8isort/deprecated/finders.pynF_1l2+K x4F];nġŘ"Y5{܇3/I$9>6ApTTm;ҷ$G˞ttuE%Mu4#:[TAS Sx.EEۍǺ&[錯ʋ라W$/+᧏>oE8\^~QE_e'Gv,@jǯz.;zr MSTa'丧m:/턜5hϴ &/ \nÉ6;^ٿO>kB>6X,D chѪ+$!(P_Ц'm#IrZW>jIZo_-]ѪF؁aSX4yQq@QY'0\.e/7F39I*$ ;Z½x_DDvɨrx X̡pz6~Ʃ΃2'K_+ͨM.UhƴVf,RW+Et3&g `X Vݺ$-KP#w<YBRs Ţ?Tu?pwW0xDCwۀ|p*4l:ф"q@aҴ_ըbz @Oϒc6Ϙ]Yє邅&EKo:LeHTb_>TP*r `tÀcD)AE@obNe $#[hL3_'BIyq hI+ZOW;COH kz`/f } e"y-;:~3̵￴!ƢcUwj&ma%AZ/! 6Zl,zVM1%}@׿4Bh>'Ꚇ`V 3,@Wh_iyXCP=9KWV0SZ )]Qq]DӘm^͋ju'I %/RvBz܃:mB4Fh"qLn_Դ@@,x ߊXi ~?>I2=p}p!Y =:#`2+ _7CMAC^;+Ani:˅ -R-,)]hOnI;]gtuSŽ1Uݮ\<.f ܌R}BiWY?K4p;|3TkԄ#?{eF g̎GXM [j[nDž'ŐNFU)ۜ矁'[h¸E]whTxwm-M.#@w]ϦK[W|Dк-9)\NO/p#H W穾'H.i[Fڥ:G]3&2vD{rBcA@ 8Sۙ)Zl__ O/zui*5 ~`$=O~¬ׯ_$˜FdvHBI LV^-; A1$庛rhJqt|~qֲ 2/4DM^}ڕ[ڒ]Bk^MaI.bsf롔ǮԊ6t]B\._q,ig䒣쨮TnedtyڂY<u%.1aCWa*Cr3(WO2Ͱ.#A\MLrV CXp )k 'jFv}B3}NzwBT[~7YnCzbX(wdT8> zQ4(w/ō9 nlXĶ0xxdc/Hlb)/{jFd)s ڢ; =ucB K$k@SВD lT:=[n/6C7/;06_f%Qj[Ir $`r'Rx raT5*Y[E`1TMA}=a^5#[xn]`)H!wSUmħw"szd N+ڄC˅$^0q{Ȓ8 _%Nt07Ӌˣu9Hp;=_c5llD4[S] ?quX?PK!kbT~yisort/exceptions.py͎0<(H-z$2Ďlо{vU)$I(mSI91֒4`* "X*Ԙ$ɤԪժ7R:Sq<<@P 0{$+ I`]ii`lqٷ߯LA+^Jc$o{lX \{`9D0dZZ=gz;7ₗW8t+GJS Z.4 ZlZsHc>:]!3;ϬPbqSuHv-{nY(Yh!OQ%)pѷ;辪Aiho'!ƫ=$XJx:Ƀ\QȌޱGdv%#AᎼh] ?*x) ?敍 @͵ՑHHRi._R|{a{] oh+o Oe}cy ha{aoP\9@(pq<)+kXT/b@B~1G4k'D; IDګduFX\ˆ`v{S!4@`]z,t,~.%ȡeMnﮗPxLvĖ 4OD>E2ѰfkMqBz0լ{ж۲mȞ%=*p+>I<0X*O=BjZ RtwZ5kS*7vCkCMdMrfBgϤD!򂬀JT]EbVBtOeȡN~`5}#zIA*J_$&Yɧ:3s^Ar vRESiU)?Aun5 ut{q/E< x.@Sj -13A7z6#*/%<'V [W\bPbph_}>]_^<4B3a9zRVcX,"NcNk;ʡrvf#=sHyu@1kn_,f&e̶(qbɚ7&[.juSJ2eUíbpkn"'ӍnFz&UĢ 2>Y!h}(̪I4'mvEebm'&3<ɝ[Y{CA9w6c?1gCI6Z'N!;bEQB JVhJe< >LeCR{S2Jp/N"G`CQǤj:d Uڔ!$dAḆiڊ:B8Uc}KQS[6ۨf?Zۢ?ӿuS%60|[̴fԁ"`SL\,{!iv͵Oi~̱60s dRjSk|i֘[p[&k;;7-6CDajr}q0r!:Ku~N3n8i{t_5H>r-bkҸOMΪ40gAFk:FvDҚ`PEz(PK! isort/logo.pym @E7."Z)h%<\ф7E4s8< jnP_Z6= Zf$eC SA{'4r}MiH i9Y#\Ñ?jЂ$՝]W3--б8q8=G_Y~fvW]e RD'>bŠhouOPK!a3] isort/main.py,gע˰>ѺvBeKq)?g?a˂&je{On(yCxMUTi)pHW3Jih9ˑ0 k%H2}XK[`{M -ndaxr5d:ʏ$5* hM$Դ>xvz<}si"[Àzm,KNjgo._<^g/fǧN?O%|yk d꿲p2\崊Av $ D_jqJ_EV0<0UnB%H@dU盿,6K=~_Vޞ>oO1kO5>Frg'"s DEEmx#VR_F Tl-ʭ5IlNF{J#Ŝt& O2Ceb QU2-E 1?*`1jLHyF@tq]U0A؅8SD.J݁met zoR^)ԺQ~eb߀%{FaV&9=M1 `P%u'|F&1?I^i0pd COp͞9 R!$3?y`L*eM}{25͍>!W<"NXaIx];CٝVrГ.oghiVg_5ggSKԃmݹuEKlvM2L QMbEDwῆ>wzBtwoܲ]n:)'ƔA&*Ja :YߦTQM >ՋY~ GF3BUE$!ҋ7ڀYr4JA4!5}a Wp-Okb5@L0eQ&[<flW C9ANJ"Xk,}õ/ӮPB-BqI748ơXz@b`>if|d2fPil'bgY`nXF"=5Sqf&l2NQS8^"Ճýq]wP2kva#ubu VJY@_LHlxZlh.~KƶC&r|A5kIHGށ@&ۚ=J9-4(h4T48|f{4B5a"g`$p *]3RJinT,EHI[L0g&O1(D^`Sd{/ /axRajǽ&SӢ0z<"ZWXr9u/ Ӏr4!GK0\RCQ+dYtҵy&NJ=)]5IPSeme4";dwL&cj}M3ٰZv&YyHzf>Rn&5yݏ<ފ~q K#!mZC{RncHͮ3m؇{( s}9z4&yd8%FEl*ZtJqK<GwcmZ-G9Q(p(҇vyS}VA ٽxlquGm4з VIpV3LZv֪ VK$L#w ]<L361 `9@I``O yZ%jG#]ώ`7N6& +W*Q8=%[%v&rc#|  A K+ QE5,sR P⎣niKɤ/-RYu_pg㘏gE, T=ikY$קPηL lK  f߷BsNcir7r%DA i[ɂ\J')RiqL#06ZЅ@ dƗ~1$vNX`Ɛ%A͙=Kp!|jkc,@gL!6wzFL~jAHts0!00u#Cv YAX<`+O~sZ|smVJh162\Hz9x``>C4LkV1m:@󍉼{4^/c&!P@Gm4ǂZ3cꍮHsvT]p +-ч Z {O#B0r4su  mLnTSfnOV雋o.ڪkb"0Cx 7olk޻ A 2 Imr5  ZiGd/tE@QXc;og#ü6e.M^o LCsL# _/X=e ԋ*9rXN5zw&T.!hGuMtdnk@Tcjc.,a*W˅0YDEtbmVevۖR+o5&l)PX1jlCwyY,'E-[ ҳԶjl``iM\]ܢi [z%xvXҊJMڏ v0U<фF*Ϝ%jG篵$ہ$h `;D 2@ XE;A <䆾{uuh6m9Úv._Z*&|7ɹLo8s[1?r6Ud-^TS6@=< fP"ꑞp/KZk'V/VVi/,J~sAWY剜_B>lzR$v ;5N?(v 53x.s8eC͘kx5CQʟ1-e/L$4[Bմ1DYBM~^גaW_WMxR'>ux} ?d i};%2g)g7Z=8tҎ#񅭪O)tp~!Mw[iYLcXD_wFE^It% PX,F +[# dVЃl(ƴj۟ruڎ B _QV6&6_6Tŭc,cn՛ݜ8ͻ1tJ,z-]÷g _n\͸ usCazB(#Ft43A_}[ӻޕwѾS2 yLdtvZFMu]p1at8ir%du&f)VLpݦvGhAS>"$k)—éd\;bJĄ oLr}8L;a3bv) ~5#X{#{@]b L>Fxq̤ӋPG5>O臫mM+Roa ԯ+)hY>-tT] َnWӺ#EWpwA(s@teh*{ ^',˘"!k@>z?ro"N1|W݅e!ߺq7{xzPCSWN{9e~= Ua;C0ŠG[:jZ\,xvl X-[T ȴ,1 cOA_iO3o<+j UAFږᄏ>_b<=#ɴ3_mc?#NGbzSn \ ;$ 1mݾ% BwLZcǮ_^@t4||->9b;LYr#'\ l1@p+?r<yzbJ h,>j'?KY +Ox:K'ȍy&>)pe!:5>O=H {%e4Ls0>wܐ?OusjZguB=AVy;msRxGiepBC>]R)lD2eT᫆v9χVR0X]~2esyN=Zw'@.E]_bPU/379fS暊i5J_ISg4RX؊U-u=ܒ$++ڤ$HoH o<4'8HR |ł9hsr<4qR (|,m1Z@HO6)|Kp89lTd P&.3$D|q }L+N]Dˋ뤦Y5uY Ls`s݀u2WW\l}05VHQ!;PxjV[BeE}T$vbA![ܾ:Q(Xu)DKϗ?Lga tejv(7 Ա ff;ڌSI: K2P\&!SbAbRSa4m\qH o+ Dd5[R(2Z[HW@tfy&{Ɣ|w,_m8W8@ YSD'{_Zj ghZ;:ӳ>12w$Z*3?X6 qwEjJ;l"If3cnD{w#N}<7$_<ﭘB}eӊQnhټqDN[6qO'P:Ȯ~o|aUQ`PLG؇6 @A^4nqq"Fݸ{B)cU;Yא0{jC{!jm ZzI˳ ;X ;jz l]Z#̮DFD_Qӎ`qs) R1}oW3l+ i!w#*9BNgCО]8i tHOݥy1N&ycyx;K5i~VWڸILB1ETıT*Y7R`>W>ōPb,77WMyx]XV[mDL춑dV8d 5 5j4h{Nȫ `ƀXϦmkZN[)yK˘;fDnO=hy`W"Bf( -o5~^ 93<$OyXǵ[#01߭`ax]*8-'Mh"7UE3ǥ2h_g/x K -ȟa0sr%\2b-Ue6 ae)Ky4Jԡџ̳.~yepxFZ%ˉ2M_uG]1<&?;B8fe:9ve|xw3fei%%!c# Z\k3qn7dʻ)!ﻅ<< p3YP4z"nsfI/;Ɏw!S=orzAqt$έ匣U(u8pEܝ1ST8ۦ>8Ƅ5'8JEm=3_Lv}"Z=ys~or;xf%nJ)ټűj1[Ngw&i>P.rQC 6)!kR**,}Śƻ*?X^ȷK>]Q f~Bm^NeYC 9 ^`S$+y=N~if >$ܴ%9`!?|}?.\~| BxG]/yiwxn' Lr02""\Y28C/99oڣ-;aCa ]  zXwyfN8/V-CڄEs.W?F]Ut8Bu8>` pTߘ x5wJE'bP!gMc+~# Exߑuo>X-9JYOW|>NX +n޻ӌrҭz/h<_y5zPDnm`6n:f{Kb=]mvXKJ#<QʛH7}v)*rl |ڹfI޽0mG {2v1g\?M|N 9Re*9+3,cZ sp瘫d ʋ/2Q?(hb?~[͹jO?PK!S2Fisort/parse.pyr񮯘6Ų67&ܔˏĕICb r(aM\tAˮTRHgzz=%I򊯋7lMQ޲\EU6lgES-[W);Z!jAIj˖f]5_*q]@UF$moӢtyx,b׋zo8b/ST4*nG 7#FbOy]xz&}&5m|)jekp Nz,W|We xoϿe~k 𶵉y͋~՛U.nΊFclw ec؋3})|qS}ͦ$%lICҴu^޵Ʉx=%HD3wӊuFPѩF.L7.l1@[ azBEbʶh8HVu' fŏ)66˄%pz 7(ox) & .zoq":OŐJ#Xb0W Q ]7(RkJq c!#Zj Vfs Q'v$)qIcS$&i:l2D] OKB?g6èciɺn XȝO0Wn+#:s횶ukf1ѰT=`^F]< ,%悧QښE&G4i>;q `e? \ UUr8"Ϻm>]vk*-K`Bh23*0r[4eNN`_yssUf|.`(F_| j+(EϒkLOF`؜ΨJ xm65}H{(9co 08+/UQIL;{ЗR8 ×$ePwF\Zs?O"Fć:BPFf+7yppKdrv[|RۛjhIGx&_~G&Q$J:&{4b")U2Xɹc#zA܁aOwjmxI8$QX)h l.dp6q#5l$!)HAY8*oGH<>3u{}~~~D`.`hk%$" 75?8lhl%F14s7HFBM5++`. kW{~N60A1h6iϘ#^ =5wi~\R}+A$ 1K&ܠF#;.ͳsb Ì)7MΤtU, 0o AEZ=tS-2t{I85ʩܬmLA@l|ڡQ/Dlw[Z4?C&9,2Ŏfl'<a~AИrEG2<1= hB>w.6GX'OϑCBD-.Jʧ|Ќ?=ol아@e2[sETLGFHe*%%oJ gf\pO?ʪ¥~8 Zg]BdXbRF1(&xLlLNǶxE'SIR#=L ǞU"WU</dQ@.KR/LU ORԉ1\e:ucǾ:5spf8ZTe{,Vho`h7΁r%#2QI%䖉={89'Y{B4mY&`~7\ ֒ŦΠK%a.na/M y*f,lHg"*%P։OT L#E":FE)[3%NJz u/L UJ˪4C0UFA.70ɼY٘S+=Rc`h /R7dZ `؄ӢS< 5^Xa'T)8'7hhy%Q\",Mjy^HPX /#YuLH2Hv[N-K :8 }%]&ib=aoD|  .qJ-$yxwt4>Ri<39Jc(Kj}ÔTA c!k:މ]j(e 6HvkS[($_1}r`;MAW)B(؎( o04f}ѱ}wk`26)?OT>  i0nrQ'A]98ֵa<ʯ]Eݩu* fgu C^}2J%ʱ{ +kuް wor!w^Dr|nGw"uX6sRP\Q9 Y W"؏/' !d? 5_>BGok)_Z |k)a8ucH5vU7A 7$βТvϘBQW/3yÆC$D|#%.yKc]Tv&D5q\M%jbk.X2jg}xHK?)NfyªRg[rRuL`OԢ'&q s:+r?BQ p>;ĜŹbW#Cr&*p3 .񸸫vdW >y}Suzo0m&Z/8Nsx9 ?|b .x5jɒn7ҍ&RJ>֋}.z\ Pb*s6̜gx;Om=ŚjYVy5r\evY8d:;PCZm|&]#/HRوueLq^-l!DEʼxib,}昱D>bb;957מ0ӿZc3QDt֭8|ޟc!t~LWWOE]k U =v\F a)ʆm:Fy zR/y\'fi!x!» o ̠lڞ;,|20{pU)uEK}=7vom@x[_O'} WFjZe|Cvܢ?x}`ez}=cI6Ca*/ՍxS)įV  ۑ#vH u\Nr^Dx$6?:'bzd7E*l÷ն} [iG6,~w3Ca]&ĸ] LyOɅ%al91XxBJi1HP9,N0v{+iI(9>`b-Hد7,,wz{ys}K%Ls? TOjmK2u\q.O_841 ; ӂYiBX>ק>t4`5Z6PK!x' isort/place.pyVmO8ʩRҦו8 B[',xw}xv(ر',j ɼ=3IHakV"E91BF5"m-A?0*H0)$I&^dĖrc><ڄ JLyA6>~ ƅIBgr;WN?l`BQ5|yQ=C#c3wspp{J;tZG~Jlp4$'GczPw*LS1_\]^ouC0$c&MpxGVU2VVLxV[0淈LQLE{}{u`s]PK!isort/profiles.pyTn0+R@)E='V%$&I+8BNė>r8"N5y+ I^5@6w GeEBu!aFNWEȾf?TUh>obӬQ MW ;߲Ou)^*DK%93U'v^:2nd G!@8=&]O쪗\xBc{A|s1.j0~5Wu.}5X;PiNpǹ\ Jr@VּQÓj@׌x. =1(>ʤ|HFF~DQClVsDчUD;Үu<*@5IqFoXQE9\e -W|s/p0"⤩&Mn1 WQ =K(**q߰3k=)Kܕ}j8 zeL acŢm;9|=y+3鋺bjf۔}V$JIOP2,,ړt-Wyg2[g^us)?,8q^(iͻ?{%l#F4-;=5p}E*]x{~u}syru ǫ3󿃜~<:19͚tS?'(>O6PH凫盳kiSxYzeg7GBpƒ$ZGEݧIQc`M]-WȲu_xpZg՛A7?ꁙF7v3-`-hA+u[Ԁ zu&V/h5p@Uѓ+?Nޝ7'W?%!>kWOZޔقO#(& yJYdUݫw4Jxx!%d\)E5;0@L zz pۘ`}U~&U}Z  4W'WH ! wT?)CaNjgҚq &z_.i:i<#!5 Eiqզ߱mQh񅦷mDuJd%l")u/dgmY i[YANlvՆ26Xǂ}  {Tx4&p ?p ؇?Kuꇡg3BwRPuWޣVO97T(s|zyăp]x 1oUYϟ -yj߿m7ȑ h2PP0c6+;aEҦ`R)D0S(Vu*yAfP`p-럁̜3&b ߚמG18.3Lev96HI`-6t=$9X˪eԡhAZiUT92mQ/؟hBҦ`0@/ #ME>Y1jۓ2<;s[??4+O[@ہt1FS8n$]k) %L@.?e9*QU[{ y4KP, Y#^y*2Ο0MG(X4 H-HB{' ߂!rvqHO,(Z{ZX!x 7yh)V82u (ҴaXӎHKCz q,h 8pik8F״ ]A^b%i0u ,,d@xg=fsd^G/M= w/)nusx2z /gx\yg-?kۺe5T:{8n`y"KK'2.:Elv/K,U`nYe}E- P3t])m\ ,#[jj%)D>V )jj4)&CBCI"雵!сd% q"FR)c3xua5NVpf  ;}H=bYgtZGӊL&4^ܜ_/>gm7iT[OJ拚$A4 $(v9 JYGV2{E] n Ę!Q]i(JdQ7i<lΜS[3vF(MLTF\fu8DiNDK 1mTCTI ^99 .ֳTp?/s"Yn)3ˏFB4WJhj1iIqb@p|jlp2OOqy3h7"QG(xwGbk`6,+tUnYS$کX'ߚw$nUо99o=D=/;p]6 ڏc_<#"ʴ'W<v ,XaFv ɟyŮbU170X.G6 HOtv/X~22gi(ٙtJySYB4(/;k Aw3! ))z\]~YBbpdbwu56dz=[g,<0`/]MyaT8 cG1Hbθ8lypit ڣ;e8vT乀#q/lЬ;ŇCq3'${B009#$L`lrsL-`Ѝذ1]]~ b?!sqaF3C IMufp54PFL~qΠ)ӗ@ Z֨glj vEftwR,nX腞PCoN\i;>w2wό5Q#|mt$.MTMde^>+Ŷ_5RQV!7*c;1dEU:*ء:Mr-2loU4sVC ض}EtD<"w#NG@*T@;H$w$G3+|(VZ3~ie+xIBJ]S8+5q.N9v@ .3Q~4ob[؈eQY.o? k. }\gV޾bY!4Z7 a)rhʇmA$w:֭hbu gdh؎;Kdx*M<"|Gŵ}9i@(VǡPQ.6y¹0/3jv|qS8qm2>~;Ogq@S`P!sTXce{7q1z,8GW*a|LMɋ(-B.J}Ӗ'{1D0F{`\ņ:1!(H/APfC)[Vzs$Z&aIXd˘H[5s 鷓%TM7N8hy1-J ?vc8Z ou%6h1%s AR^Bc2V`!j}Aح̝^@aO? BIcR4n$0pc[@#D°g(d]ZEQE+ +;w+[,Bx4SP8aG4*493ߙ VDREM9Tؤ%TXӯ2d@(q9t/a*M$A_Z._u/W%a&aWyFVn:WBtaJT_gR\+{ZLy ɍ]LF,5x5V'C dƭEl(Y1sooݵ'P(Qٙz5<;]Fo3@OA6۲_?bFg=N/>Yw(a8* 8:窮qm{yǽYGov GH+ӏ}׶Y7Sc0bLhx#I(WG6՛ S穂ͮh1|ZC]mN%3Yͱz HxwŎC 5mQ>^w}缀b'l6|͖P7nrKl}:6y r('.S p/|FmuEy@ZMS (ԫ?PK!Kisort/setuptools_commands.pyUmO0_q2BKX`JLB@i8l}g)i%C=wB*i&R+]i/Q2S\lj<2#2LQ#65*hQ2SFL{5:labLbrp}??\]zeTk3T7l#/o5PjâFBT"UxX4DK4H3Sh˸̘[[LG#ȏR+h-$\ǀat z$3dZ rirdIF V Ѡiy anٝ\.if}0 Wy:ғ`4zHl[v|6,C9Nl;vN耦,P"IHF}vױ7Cc<(7A]aczR|2s'QvPѵvwF6:ȳ"v!vB3͆,Sfdc̪UCq,skiʐoɅoW# 6iRUmo1, ]Εs;.`;NiN G'xXaB)Lj`v1sA(}?mauyt ?LݣR鐽p[#PK!XFv} isort/sorting.pyUak0_!̴ 60#- c}MS8rUt Y$˖Ӥ-%{:=M%%Vbw-kLZ 6%,wnl-W MHS$)RpJ.Vf@ZmZ.XJ/Vc3Bqކ|_{S B^XC6j|b4!}ՆX=uXt\.;SRV0RiV֕aǶ Q(h4-CIȇPxf};cA"7i~iL>$+xjP=V3ӆZ4 -ilV\vjۚ4I1լ/BXS5NcPN}*4r+al]`rAnUA(7fϟbcfLqb+NT+Rz_4LG{JŸ 4xiCxQiw>|lAh/|RA/DXYPpٞsr唏c>߀ۓ-}zxw~ I^=Sj+-W7*Ri[htnN/yCDot07'$n]rH|$qIxzŅ'R\KKUII-.2tybPBw ƴF1? 3&`8wcbXJ  DT <=l}6}j_.N^k_ No㮕+k6$ sc9:!jYz!/3 FOBfAc""-R~)aIub^2!1~RybDIp3gq eh'e!ZM.Թ'y^ʄo^҉:r X?fV 69 ^rСnkf9IBXh|`cφ!`i!ab鸀06톒D t{Z'z#H4 ST. QR9 X珞H0~8&>Y>]q:c*3RAqe1vR+7+_f)&KszeG,'YPô< IGɷv&\$2O["PQ%0ئ|\8jAb W E5PA"cmY|jB-$'egdB2*@XN5P #{P$,=U 7` h;Bhxx@ztBP%Ҵ+s>tncS3%niGxi=LUYن1rxOZ+B[ 錔S6NPwJ ~Ȗ_džְX2yan JFsIFyR0a2'$?{ܑ(c9f'½ls3Q-4U8_ 5AE^zN19, XT!<4 `v\rZ[绹GNṇ~[nrR!ZЋ?4Y:(wUI|D6WEʒ#G<;W_ Y;0{;qnrzb~X Io8#<||4?@(p(fgcvbpbŤ 4lr?Ԑ]݁s*Erq#\HY o)^2`LfНcP3~YFT:c\ LU\Ql_!9x׾ d'n$9-U)ȥLyjkͅœ3<+췊Rm|{ x7TVZWK-Wo,E"MveqͺF%y{4^ţ8)sƆճw%PEKSR1øf@6@G~@zùcUSdRS A09:J;=z{0jlxZA)M_tc4vn_6`Bq\IUnhnQz;ְ35 8% wHT5NԾـgtQ,{ C@gTz{t-)RPƫw5qȜ/Qo'45t~6a4 57 g>ЃxYqhS qovsZ 7Qj'!{\-W('o'f'Vig e4)1~x%⌊&1Ta/P9-+¢8Xo b1*&."`U'-S<]kl3V- PK!{# isort/stdlibs/py36.pym;6 =W8w̸]P$$1˗At@^/M>HxGL0Z'`JpgtOu2ry>O_7WV&7Է:Rf>豬?6NOcl|yb/weӷ0r޿{w?gt1.*vPF tRq/|3zŠ kԏGήÇ_,b, o˞8@ou G(hD6U ;ďZb fTS@BF{ؽ)[aĽnED) >Y,";BFA1zM(5dew:Ŧ!b\Hmd#A|nciC[ ' X*2٬qtu7tX/Ԍ_Q<ժXWbjwGS-W7ufɱ2z5ţ!zr+yНavzR i pY&ũ2G&Ψ:``2C(EaoӲ",fz-b-r̭, _uMrEq˿PK!S@* isort/stdlibs/py37.pym;6 =WؙJdM EA|.{ @I‡IO>==~_2@+ \NC #:܆26ZK>=|:}:/ߟ// 2\YhhkqF>LB^~l΍&^ܞ64 <ï_O/SOi{>+F/bUƥ:lnhGu[ЏJ]FCv͇`xR/{=D }|("^IkghU?2}%F67l>f8U6Ũ;"d29CF%Ni.feEU :)49r>vT$ޘ$"\k lB3"u Qhx! ggSE5TUt1 z$.)wgIȧj1ž9sxɓ 3s`j<1"Se-lX VVs $'Ǯ$9uB%]-hSKՖ&T`g+!a*>R;J.ƲҲo=dz5XnVMk!¡|R2#!O.I2T,c@(ZD9Ʃ?RTC/ek? mh?[;"˵eo^G#9kŠB MjIWɳwi86nXxAB1Esrk{*W4(wkؙY}yZ"DSw*mx6>-,"]NMZLhşęuk5)AܮIϔ] :);Uvt>סj[K4DnT1$7 Je)TȵoILAKN}N\Q{fỬ6:shH! JtG? Z,F'i$W=ٵN:FU a}M\aVG,W!ocm fm~"VOqW!y}˿OPK!{'% isort/stdlibs/py38.pym;6 =WؙLtNf.P$1ׁ2d+|Xa% 40m(m/ϧ_}y2"@0!ÕՍat-hnC*=]?:u2Zyûn"Ye\6F*n/pPXP!O5'i1d|W)5C$LJa9. %x|HV/X7KzI_bdsCXmSe3]ɾ#B&=Dht^ŸnVFXqz@H[ݠB#kGPHiL"ɵ0)4#RUQ#Ob,{+-ɞCi,7UElm 3P/)ue'MԂqKji*0f dYd \A@ *ӡzǾbڸkgubTO׼`t27{Njv{Z1h9Py$ZAUn/mY5>ꃍ;^;tP(|J+`ٞJGvF{8vzޝ&F[!^@)mO KvH%s'!Zg#qf]ZF>E!pP2kjd9}FhJNn4ݸu 5Ulg>ЃxYv9oh3 rozSҵ#s W^ig.;\<*go'F iQG h8Uc|ag"뀎xwd4lWeqwFkek[Y~ltҲUcEq?PK!' isort/stdlibs/py39.pymO6 F;Àv{!KE(*߰>iHzXN1DϘ`% 0 )p4|h)y˷Ꮟ _gh7dЖSF>So1?6X//n/uXtfOi;-:=Ѝ^8su@&H-Gu{ԏ{'QĘ]1^˞c8oex ׅhDE`u(} `e,%}I͍%R^+RRM2!BcG?+Yaĭ*"mtg G'׎*7¸>N4kClFN1xM;X]mS,p!4UPcUE1K~N'R I8L/~c] 2烗 2 1UsgO=gh8*{XTd]]3dq~3Z$9"qJZ$f5"V^2/ J|P_$ S٫]i9aVݢwUۢ l{)(u5J ڢqڮ++eX<P"\r>d1sm:*LN_~t g?[c/Bũy/vh/$eRbԮY%1֛$VݾǪiTlܚڡBßd\I'>lUhnP:z;ְ35 س9/\D 6HT41 JIGl[l|Z3Dh,Lh_ęuk5AܮI]:)Uvt>Cdu,QS u3( =e6S ׾&Zt =vX>ţ!r|+yatrPOZ,FG)*W=C:&UaWn}Nܜ aRG,7o1'ocnmf=ZexǶՐ~i,=*딎(.@MbjOh:Zl,A@** ,ѶjZ2?ۗT8s3vSsAdkyӫ-Gj_g|;f+ em۫I#x(EQ*+]*iL`$*AiFұG'FG2ŁcYL(ǻĆL6Cۿ߭G?%4lf@Ӈ n\frtUvX˝rfv]I_+vĪH[ j}S:PK!Bhx isort/wrap.pyWn6}Wi>$H6ͶI (6ЭI`;ËHJm@ glꖑEݼyRo%aoM^={w,"7 *+"gCrQ@S_O]ߥg7W9U,_ڬIzI{`WuT]m1F5ҎpyK*1ZҊw[6#p u3=pQ)(m6cuqA?TB@gs (J`yʡ k6`Ӏ7F^H%3~[6m cD!WC%R[SҴ|H(("t#sIJG,!^|DG 9GzU/k3[k92TmI&81z &?EV|Y £47dmD}2Ҧ5\ٻb)kST̒]\R}esUz[˗_{ʊ Roikˡ̢ǰZ]xU^nJu!ώO5:-:^\їtXLO +6$Y4]K .4 djR6rb 'rtд4{7={pw:\vZ{z?}Z?jX&jO2Cj5C5 q#['I*hx$ Iԑ. z 8=Mk"_T 2d.*hI7QsVTba`wM^!4O3B>HgD]m_rT0kY2g|qGdt!@L K5W@͏~h_I_n'&ƴ[d D¹KSv4k "!SaK_RGf6sחq*l\;V18.Q-2{{#{#}'66 k)~v[DVZCWlGWwXqD~sFPtY͍$T@?AGwWic$:n fxUDxr?_ƅ|=fMǹ+״=G h.B5qɟFXU4J;$u!%Js ~hcHB>uh - \1(r͖%"+ SBJR.rBH ,)v5Ow%yV<$TUqIQvz |VbEUrݎ%"ip )E.x#c@ %aF![T௨ܻqfƇWo|FKd6p&a^jn҄r׽(_-CӀJB÷)*Wd"P߆Ga% P'kbLJɟݚx-7H ϐ٤NB=F1K6b;U#U,rJ ㈿oU\+73JxRh^ѩE [lR&PGcֆ=d%4Q`66cU~/Ad: jȟǒ v"Y ʙJha LD(2dQz2REe4 P#SZT\eAT7υ-L$Eɸ)vŠnmhsë-q|ր\-gU̽ K\8M4^Uʄ}AYG%=ɪqSHG^r"&e9H,L@zlXk3 熀VҵU<W|Mp;mxvdyG3ۥ,ū˥n]ZBGW/l U՘bM (aom czy0$DFJBmFƍvd`/HT(jRI @[w8gReE؛>F@~—"=1q M>wɼݼv[oaw'dV5E@,V:LL ; `yC|hF׌ l5us [-CI2PIp[..n8B8j vJfMBۛp9+o/À[lb=yNwKv[u3K`9uj п_8:ݺ];]wcQ#=lrm@7ȏ2w۰3!hSPn"7>bM?wN9:8*04ns-`gBj%}e[HxsGyB {ܳj oeUQۮ]>Ȼ }}5]ݑRj9S t< Qn(;l8O$i.O}T6F;6&pjcGLK3.SNEvĒt^{>Vgdc;֭N8+ZmLkBרnSg&uОÖU @,vaQ`y MjK#[{1FA?i13JQ(=mb:AjA cޣ:Iuaxh'mǞ4㛧KmL8H%M|լSN&O(_MfXgԽe=vThSjۈ6t*;?y/~$}x\iK-6k Nc4=t:? 8]}etSd>,r`gvx_/f퇽s:;\-bV&W?~utIuG?uǓhg{QDe_Oی $)ׯN+O`_Wy35pT1̧_maPK!H^&isort-5.0.1.dist-info/entry_points.txtN+I/N.,(),/*zyV +:%$3X/9?771/Z` "SPWZ ̱+PK!}BsAisort-5.0.1.dist-info/LICENSE]RKo0Wrj%}XK02N9pWGl3$mՕмnjMga- 䮱C#c?_Gw"<4` =MC Cov<hW8ma6pcpd; /h:߸tC#\oiڹdh.Mj:tU;z_J2LJ`u`sg2ylb_lj#e؈X 8>=REQKxtoyLT/yEo܇KeI>ei,?zf$;vV]zu tb}$**bf4L<%卑%529P(OHO` R5e_?Sw8Ƈ͸JYzTjV,x O&Oނ-@C`_cbNS;̴Lyfo_Y'|hQzƉ)K/]ph\T&:; F- pH./b{WXdu]^PͿB_wyݳQ+avxemǩ.&,FK VgH]og.drz zfwx/8Yj&>.ab$x8E,ϵ)#OO8170266*^!_8paos(-E Sw`~C&Z6O6o؉w͋^ny-Uf:Xp /`CHL;Z!Ky. WdS,aqolC S&K ])|arޯ'Ñv:I~_W؁!̈/d&Ns!Yy>*a*[1G ;KZw02L$$jq1)1׎Ga'Q- diq|_٨lPV8^v`SfnP0uRpnnM_ʄiS<@׀6\RDLӆmTS 6TG* oInay" ikc??0 Xg)za)=!˂̜g B:WӺ \]=H [(4Y0~aJJdSRSl#IpXK_ֈG6teHb ,0{A0L 0hr {%SS<ߠdպQiHQ-2Mxnـ~K?O~o-Oo[xg5gAO!.+3 +.J8kormYZ b $[?Dz돔[@gl+ՒevHSyKܢ!fayYFk;DE¨싋d6 ^% hetRk28^@F)K2ٗക6#%ke.ܽpYZo+  +'NOSCx 63]¤R؄MҖAhtѸ=ӫ/ P }UٙFIPĀr_CZBZOg/R&㦟ro?wY6(AjPzn/ Sb<"D85 F/ CA'"? 3E@PXh3p8Zj8)N4Y[XZ~| f?aJЃhv(2@OxNjM(ct&L >#m:A;Ӳ@΂V[co51;  J S;}K`"S0P5 D oiF @* ZRQp ]7-d5/m]ٹ! qq 'b8(tKrxIEA]g$G^^'l[ ۩CPZ4lH&dCh;0JT Ees"(6 x3 [6|5C|D| eram{ (6\IѫQ^M-Z'CsJjѯͦa/@4=،RFIUh@ =HX$SV~[ aJ>uc:b9*ĸ{E|$\saßcWəEoGSA􄱮caNf@>7W{;#x|鏦_lY . hiƨd-r&}УhzˏOH~HKJdJ̺Xr" Pۨ2e 3N^_: Jx<7BZ}ҭP)' G0uz؋ܯs'm'm4Ǖ2h*n ]^>Lʈ7N81W#;⨄6+tϑ!ْI`I)F_:`1xnTFۼҸ1U2+Ȳ.R^}?98_ō;}u=mcb}kMq:1䜬*xQJk z㐧 Y{j3FbT@|ȕB5 .܂wO#. *s|Α KC<֙6o'2`f?35 $<gx y8)UƜ;u^ 4x1 9C tw!"V7Z(ЩPi'2l~~Z G7"]疽 F*g1B`ck}Lm2 lJm:\A/=%~FAi{M18ER.Oa@Yiۻ_`],#[ާ@&ZI6{i\?nGjvZi;h'>JsZTg+3]=cʁzoYs@.ѿ3SїT p:@ װѢ:0pİЙ:clg<ɞ= BQ$9a?I g[BSAo )MfLQFo" XOELUC4cObL$@A{mm/@Jsas.R =SNi*5a @~dpR N`H0B^D%>`{դ;r͝k[x0h>:EAZ H!hquv;^JtpMS{E z*T4tڑl.#r+Ҙ@t?ĊjJ_)G6D'LE{g$ I6Q6; `OWi*L 2I8IVg}$_ޢ}',c@Ì q6GդM\/ u3n7!RfNNo)NjӒٌ8*p`Ђb-ś>\IFM&Qş ӗ2Dzَk0~dA|$uĝV(&_T$"誀u55cWZh_N㴛 !9Qm&XuXG65o;u_ѡAtzl^Yw(q' AŘzg=,%Mz e dہj]/h Y#AR> :+㽉5V #v!0,!?`,kRLV0>UPJ`8݆zxrìH馉`zڭL48␆*j Vr"[JOfVkw >_Sm[2S LU,V"w )"<&2 ~'K9_6#h0tS&sHԚu!x<-YEAj^8`C{+w8&F45)ciE;SMMvIGFʚɜ8|;/Wmx|PK)H̞b&/LYJ:fFjx = K6 })3瘻ԐKLF[QN6*xyrr|X6P=u$"G;α'`ҡ7ەHT}5V6 է(^hʿ7WuW߼~PdڅInrm+AQ~jQzνZ V o:Dx`̼ > t$rV?tĜ4H*q $EHFFb\mӣ"]"9n 'NA8&mLaڬ] ٦/U *#iQ6HI uRKL_6L"o]qd2| I =$z#Q a|Ыzps7Qi:nV}!Yn'f.'] G֙S_)wuiܼB&AoƄ_g{'oe&۳Ɛ nt<l7{Z}|v:U$?a8q%,W%&aX]inJyv`PG@ t_s!d sX֖9.<8QjS'l=%z f14] *l` S\CG=GjJ`βQWRj(%6 6>zz@ }aD]}j` :DdD}V%O-GpDcROJLאQX ܃oL-bk05"aj*?I >}k*տpHz ̒<Dem4 )M0D!ɥ$b9o B^}׆#\T$OHpZO⮃Y\w۫2`Wk߳BAvc aX;.Mm*N(.O >!6!)z޽XŰKUؖ`REΒP)!C|"Z #O%=|'Ua^mqG:*i PK!H2V efisort-5.0.1.dist-info/RECORDuɒH{? t/9IX\0}!xJ9tUEfy#3a'&n,Dp?SL~k$Qdmt3T(epo¤0b_IC3u"qv>_@UUe9ؚ{'8N-u;`GG %ԏ-GY [zThkq ODHލG'ÁœhrbLhNiU}DI+Ax?*'ͯpj0N#膍OLDq=/|A}î& |iC&FO0Ti^] E:2(=;mކQyC,W բ]To6-|(t9@|/FCs_$zeD7^ԛD.?Yn|IRQ4O k5 PS8m@P G[I37ΪGvChZ8ϩ2{=@LquҬlSNtC=o.!FB0qKf#1Nv3 @ϼُX$7frLm~9x_Y1>C6-D#=#g))$MFZalsp+5b&> u8 rl a(m2,S9ъ45@lw.c9퉂A4ð]J2PKtvAL \SАWgT "%LMK%D`SQy@E:Cgj>k4ub@ ֏H/İuҌ&/ѪDLa9j~͇vE*RE&q 5wMcV=^?t0&ǩpz+],ypVfIe S0 yB$ePV6>ڥhľϵArW)xNϰŪi] I{1 C 0()ېBveswK{*U2)s=| ' €Scf[Zh݊>t43&+C>S\]S\k"D8D=f!ׯvx/UuJaBy|q7>9T)=٬/T"*R 4ǢQYiA|Y'`<] )ؤs}㵄7W~J@-xк&+]X@pS&O潆w!n6Cq~L[n-3.+tXWd؟yЈv/qA"=w/4XУe*<I-t}m@oj;1fɦXs:}Xuٳ̮ߤF:GEנ98QTe&r\ eqTQG-!fR}<)B:[7jװs:J>jͪmELмT:k,CU%^ Ʊ?uԊ]?Vg8(A/ǂ$7TL<ق!cQSύq4A?֥=}@Z?k5E.h7mtDXE?;a.b%}\_mԒI}"@AjWJ)zpgxFiH(*X XWOqO/3E=^kWA eEA:F3%8JMM/PK!ßgisort/__init__.pyPK!ڞC $isort/__main__.pyPK!KXzSF%isort/_future/__init__.pyPK!W0"isort/_future/_dataclasses.pyPK!R^3isort/_vendored/toml/LICENSEPK!RE 6isort/_vendored/toml/__init__.pyPK!e QV7isort/_vendored/toml/decoder.pyPK!@kt{ %Wisort/_vendored/toml/encoder.pyPK!NNgbisort/_vendored/toml/ordered.pyPK!Oj-cisort/_vendored/toml/tz.pyPK!\disort/_version.pyPK!Tϲd] disort/api.pyPK!՝1visort/comments.pyPK!wisort/deprecated/__init__.pyPK!][ h81xisort/deprecated/finders.pyPK!kbT~y^isort/exceptions.pyPK!G57 isort/format.pyPK!E^Misort/hooks.pyPK!7v8 isort/io.pyPK! isort/logo.pyPK!a3] isort/main.pyPK!h1SWisort/output.pyPK!S2Fisort/parse.pyPK!x' isort/place.pyPK!misort/profiles.pyPK!0ܧisort/pylama_isort.pyPK!?)tisort/sections.pyPK!vE_NTisort/settings.pyPK!Kisort/setuptools_commands.pyPK!XFv} Misort/sorting.pyPK!b+@isort/stdlibs/__init__.pyPK!:+9Sisort/stdlibs/all.pyPK!hy#)isort/stdlibs/py2.pyPK!=]isort/stdlibs/py27.pyPK!xГ7eisort/stdlibs/py3.pyPK!EO Bisort/stdlibs/py35.pyPK!{# isort/stdlibs/py36.pyPK!S@* isort/stdlibs/py37.pyPK!{'% Gisort/stdlibs/py38.pyPK!' isort/stdlibs/py39.pyPK!l isort/utils.pyPK!Bhx isort/wrap.pyPK!f0.isort/wrap_modes.pyPK!H^& isort-5.0.1.dist-info/entry_points.txtPK!}BsAisort-5.0.1.dist-info/LICENSEPK!HRSlisort-5.0.1.dist-info/WHEELPK!Hq#a?Lisort-5.0.1.dist-info/METADATAPK!H2V ef:isort-5.0.1.dist-info/RECORDPK00 3Cisort-6.0.1/docs/upgrade_guides/5.0.0.md0000644000000000000000000001753113615410400014506 0ustar00# Upgrading to 5.0.0 isort 5.0.0 is the first major release of isort in 5 years, and as such it does introduce some breaking changes. This guide is meant to help migrate projects from using isort 4.x.x unto the 5.0.0 release. Related documentation: * [isort 5.0.0 changelog](https://pycqa.github.io/isort/CHANGELOG#500-penny-july-4-2020) * [isort 5 release document](https://pycqa.github.io/isort/docs/major_releases/introducing_isort_5.html) !!! important - "If you use pre-commit remove seed-isort-config." If you currently use pre-commit, make sure to see the pre-commit section of this document. In particular, make sure to remove any `seed-isort-config` pre-step. ## Imports no Longer Moved to Top One of the most immediately evident changes when upgrading to isort 5, is it now avoids moving imports around code by default. The great thing about this is that it means that isort can safely run against complex code bases that need to place side effects between import sections without needing any comments, flags, or configs. It's also part of the rearchitecting that allows it to sort within type checking conditionals and functions. However, it can be a jarring change for those of us who have gotten used to placing imports right above their usage in code to avoid context switching. No need to worry! isort still supports this work mode. If you want to move all imports to the top, you can use the new`--float-to-top` flag in the CLI or `float_to_top=true` option in your config file. See: [https://pycqa.github.io/isort/docs/configuration/options.html#float-to-top](https://pycqa.github.io/isort/docs/configuration/options.html#float-to-top) ## Migrating CLI options ### `--dont-skip` or `-ns` In an earlier version isort had a default skip of `__init__.py`. To get around that many projects wanted a way to not skip `__init__.py` or any other files that were automatically skipped in the future by isort. isort no longer has any default skips, so if the value here is `__init__.py` you can simply remove the command line option. If it is something else, just make sure you aren't specifying to skip that file somewhere else in your config. ### `--recursive` or `-rc` Prior to version 5.0.0, isort wouldn't automatically traverse directories. The --recursive option was necessary to tell it to do so. In 5.0.0 directories are automatically traversed for all Python files, and as such this option is no longer necessary and should simply be removed. ### `--apply` or `-y` Prior to version 5.0.0, depending on how isort was executed, it would ask you before making every file change. In isort 5.0.0 file changes happen by default inline with other formatters. `--interactive` is available to restore the previous behavior. If encountered this option can simply be removed. ### `--keep-direct-and-as` or `-k` Many versions ago, by default isort would remove imports such as `from datetime import datetime` if an alias for the same import also existed such as `from datetime import datetime as dt` - never allowing both to exist. The option was originally added to allow working around this, and was then turned on as the default. Now the option for the old behaviour has been removed. Simply remove the option from your config file. ### `-ac`, `-wl`, `-ws`, `-tc`, `-sp`, `-sp`, `-sl`, `-sg`, `-sd`, `-rr`, `-ot`, `-nlb`, `-nis`, `-ls`, `-le`, `-lbt`, `-lai`, `-fss`, `-fgw`, `-ff`, `-fass`, `-fas`, `-dt`, `-ds`, `-df`, `-cs`, `-ca`, `-af`, `-ac` Two-letter shortened setting names (like `ac` for `atomic`) now require two dashes to avoid ambiguity. Simply add another dash before the option, or switch to the long form option to fix (example: `--ac` or `--atomic`). ### `-v` and `-V` The `-v` (previously for version now for verbose) and `-V` (previously for verbose and now for version) options have been swapped to be more consistent with tools across the CLI and in particular Python ecosystem. ## Migrating Config options The first thing to keep in mind is how isort loads config options has changed in isort 5. It will no longer merge multiple config files, instead you must have 1 isort config per a project. If you have multiple configs, they will need to be merged into 1 single one. You can see the priority order of configuration files and the manner in which they are loaded on the [config files documentation page](https://pycqa.github.io/isort/docs/configuration/config_files.html). !!! tip - "Config options are loaded relative to the file, not the isort instance." isort looks for a config file based on the path of the file you request to sort. If you have your config placed outside of the project, you can use `--settings-path` to manually specify the config location instead. Full information about how config files are loaded is in the linked config files documentation page. ### `not_skip` This is the same as the `--dont-skip` CLI option above. In an earlier version isort had a default skip of `__init__.py`. To get around that many projects wanted a way to not skip `__init__.py` or any other files that were automatically skipped in the future by isort. isort no longer has any default skips, so if the value here is `__init__.py` you can simply remove the setting. If it is something else, just make sure you aren't specifying to skip that file somewhere else in your config. ### `keep_direct_and_as_imports` This is the same as `keep-direct-and-as` from CLI. Many versions ago, by default isort would remove imports such as `from datetime import datetime` if an alias for the same import also existed such as `from datetime import datetime as dt` - never allowing both to exist. The option was originally added to allow working around this, and was then turned on as the default. Now the option for the old behaviour has been removed. Simply remove the option from your config file. ### `known_standard_library` isort settings no longer merge together, instead they override. The old behavior of merging together caused many hard to track down errors, but the one place it was very convenient was for adding a few additional standard library modules. In isort 5, you can still get this behavior by moving your extra modules from the `known_standard_library` setting to [`extra_standard_library`](https://pycqa.github.io/isort/docs/configuration/options.html#extra-standard-library). ### module placement changes: `known_third_party`, `known_first_party`, `default_section`, etc... isort has completely rewritten its logic for placing modules in 5.0.0 to ensure the same behavior across environments. You can see the details of this change [here](https://github.com/pycqa/isort/issues/1147). The TL;DR of which is that isort has now changed from `default_section=FIRSTPARTY` to `default_section=THIRDPARTY`. If you all already setting the default section to third party, your config is probably in good shape. If not, you can either use the old finding approach with `--magic-placement` in the CLI or `old_finders=True` in your config, or preferably, you are able to remove all placement options and isort will determine it correctly. If it doesn't, you should be able to just specify your projects modules with `known_first_party` and be done with it. ## Migrating pre-commit ### seed-isort-config If you have a step in your precommit called `seed-isort-config` or similar, it is highly recommend that you remove this. It is unnecessary in 5.x.x, is guaranteed to slow things down, and worse can conflict with isort's own module placement logic. ### isort pre-commit step isort now includes an optimized precommit configuration in the repo itself. To use it you can replace any existing isort precommit step with: ``` - repo: https://github.com/pycqa/isort rev: 5.13.2 hooks: - id: isort name: isort (python) - id: isort name: isort (cython) types: [cython] - id: isort name: isort (pyi) types: [pyi] ``` under the `repos` section of your projects `.pre-commit-config.yaml` config. isort-6.0.1/docs/warning_and_error_codes/W0500.md0000644000000000000000000000256313615410400016446 0ustar00# W0500 Warning Codes The W0500 error codes are reserved for warnings related to a major release of the isort project. Generally, the existence of any of these will trigger one additional warning listing the upgrade guide. For the most recent upgrade guide, see: [The 5.0.0 Upgrade Guide.](https://pycqa.github.io/isort/docs/upgrade_guides/5.0.0.html). ## W0501: Deprecated CLI flags were included that will be ignored. This warning will be shown if a CLI flag is passed into the isort command that is no longer supported but can safely be ignored. Often, this happens because an argument used to be required to turn on a feature that then became the default. An example of this is `--recursive` which became the default behavior for all folders passed-in starting with 5.0.0. ## W0502: Deprecated CLI flags were included that will safely be remapped. This warning will be shown if a CLI flag is passed into the isort command that is no longer supported but can safely be remapped to the new version of the flag. If you encounter this warning, you must update the argument to match the new flag before the next major release. ## W0503: Deprecated config options were ignored. This warning will be shown if a deprecated config option is defined in the Project's isort config file, but can safely be ignored. This is similar to `W0500` but dealing with config files rather than CLI flags. isort-6.0.1/example_isort_formatting_plugin/example_isort_formatting_plugin.py0000644000000000000000000000110013615410400025306 0ustar00import black import isort def black_format_import_section( contents: str, extension: str, config: isort.settings.Config ) -> str: """Formats the given import section using black.""" if extension.lower() not in ("pyi", "py"): return contents try: return black.format_file_contents( contents, fast=True, mode=black.FileMode( is_pyi=extension.lower() == "pyi", line_length=config.line_length, ), ) except black.NothingChanged: return contents isort-6.0.1/example_isort_formatting_plugin/pyproject.toml0000644000000000000000000000110313615410400021170 0ustar00[project] name = "example_isort_formatting_plugin" version = "0.1.1" description = "An example plugin that modifies isort formatting using black." authors = [{name = "Timothy Crosley", email = "timothy.crosley@gmail.com"}, {name = "staticdev", email = "staticdev-support@proton.me"}] license = "MIT" requires-python = ">=3.9.0" dependencies = [ "isort>=5.13.2", "black>=24.3.0", ] [project.entry-points."isort.formatters"] example = "example_isort_formatting_plugin:black_format_import_section" [build-system] requires = ["hatchling"] build-backend = "hatchling.build" isort-6.0.1/example_isort_formatting_plugin/uv.lock0000644000000000000000000005043513615410400017574 0ustar00version = 1 requires-python = ">=3.9.0" [[package]] name = "black" version = "24.10.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "click" }, { name = "mypy-extensions" }, { name = "packaging" }, { name = "pathspec" }, { name = "platformdirs" }, { name = "tomli", marker = "python_full_version < '3.11'" }, { name = "typing-extensions", marker = "python_full_version < '3.11'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/d8/0d/cc2fb42b8c50d80143221515dd7e4766995bd07c56c9a3ed30baf080b6dc/black-24.10.0.tar.gz", hash = "sha256:846ea64c97afe3bc677b761787993be4991810ecc7a4a937816dd6bddedc4875", size = 645813 } wheels = [ { url = "https://files.pythonhosted.org/packages/a3/f3/465c0eb5cddf7dbbfe1fecd9b875d1dcf51b88923cd2c1d7e9ab95c6336b/black-24.10.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:e6668650ea4b685440857138e5fe40cde4d652633b1bdffc62933d0db4ed9812", size = 1623211 }, { url = "https://files.pythonhosted.org/packages/df/57/b6d2da7d200773fdfcc224ffb87052cf283cec4d7102fab450b4a05996d8/black-24.10.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:1c536fcf674217e87b8cc3657b81809d3c085d7bf3ef262ead700da345bfa6ea", size = 1457139 }, { url = "https://files.pythonhosted.org/packages/6e/c5/9023b7673904a5188f9be81f5e129fff69f51f5515655fbd1d5a4e80a47b/black-24.10.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:649fff99a20bd06c6f727d2a27f401331dc0cc861fb69cde910fe95b01b5928f", size = 1753774 }, { url = "https://files.pythonhosted.org/packages/e1/32/df7f18bd0e724e0d9748829765455d6643ec847b3f87e77456fc99d0edab/black-24.10.0-cp310-cp310-win_amd64.whl", hash = "sha256:fe4d6476887de70546212c99ac9bd803d90b42fc4767f058a0baa895013fbb3e", size = 1414209 }, { url = "https://files.pythonhosted.org/packages/c2/cc/7496bb63a9b06a954d3d0ac9fe7a73f3bf1cd92d7a58877c27f4ad1e9d41/black-24.10.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:5a2221696a8224e335c28816a9d331a6c2ae15a2ee34ec857dcf3e45dbfa99ad", size = 1607468 }, { url = "https://files.pythonhosted.org/packages/2b/e3/69a738fb5ba18b5422f50b4f143544c664d7da40f09c13969b2fd52900e0/black-24.10.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:f9da3333530dbcecc1be13e69c250ed8dfa67f43c4005fb537bb426e19200d50", size = 1437270 }, { url = "https://files.pythonhosted.org/packages/c9/9b/2db8045b45844665c720dcfe292fdaf2e49825810c0103e1191515fc101a/black-24.10.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4007b1393d902b48b36958a216c20c4482f601569d19ed1df294a496eb366392", size = 1737061 }, { url = "https://files.pythonhosted.org/packages/a3/95/17d4a09a5be5f8c65aa4a361444d95edc45def0de887810f508d3f65db7a/black-24.10.0-cp311-cp311-win_amd64.whl", hash = "sha256:394d4ddc64782e51153eadcaaca95144ac4c35e27ef9b0a42e121ae7e57a9175", size = 1423293 }, { url = "https://files.pythonhosted.org/packages/90/04/bf74c71f592bcd761610bbf67e23e6a3cff824780761f536512437f1e655/black-24.10.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:b5e39e0fae001df40f95bd8cc36b9165c5e2ea88900167bddf258bacef9bbdc3", size = 1644256 }, { url = "https://files.pythonhosted.org/packages/4c/ea/a77bab4cf1887f4b2e0bce5516ea0b3ff7d04ba96af21d65024629afedb6/black-24.10.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:d37d422772111794b26757c5b55a3eade028aa3fde43121ab7b673d050949d65", size = 1448534 }, { url = "https://files.pythonhosted.org/packages/4e/3e/443ef8bc1fbda78e61f79157f303893f3fddf19ca3c8989b163eb3469a12/black-24.10.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:14b3502784f09ce2443830e3133dacf2c0110d45191ed470ecb04d0f5f6fcb0f", size = 1761892 }, { url = "https://files.pythonhosted.org/packages/52/93/eac95ff229049a6901bc84fec6908a5124b8a0b7c26ea766b3b8a5debd22/black-24.10.0-cp312-cp312-win_amd64.whl", hash = "sha256:30d2c30dc5139211dda799758559d1b049f7f14c580c409d6ad925b74a4208a8", size = 1434796 }, { url = "https://files.pythonhosted.org/packages/d0/a0/a993f58d4ecfba035e61fca4e9f64a2ecae838fc9f33ab798c62173ed75c/black-24.10.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:1cbacacb19e922a1d75ef2b6ccaefcd6e93a2c05ede32f06a21386a04cedb981", size = 1643986 }, { url = "https://files.pythonhosted.org/packages/37/d5/602d0ef5dfcace3fb4f79c436762f130abd9ee8d950fa2abdbf8bbc555e0/black-24.10.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:1f93102e0c5bb3907451063e08b9876dbeac810e7da5a8bfb7aeb5a9ef89066b", size = 1448085 }, { url = "https://files.pythonhosted.org/packages/47/6d/a3a239e938960df1a662b93d6230d4f3e9b4a22982d060fc38c42f45a56b/black-24.10.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ddacb691cdcdf77b96f549cf9591701d8db36b2f19519373d60d31746068dbf2", size = 1760928 }, { url = "https://files.pythonhosted.org/packages/dd/cf/af018e13b0eddfb434df4d9cd1b2b7892bab119f7a20123e93f6910982e8/black-24.10.0-cp313-cp313-win_amd64.whl", hash = "sha256:680359d932801c76d2e9c9068d05c6b107f2584b2a5b88831c83962eb9984c1b", size = 1436875 }, { url = "https://files.pythonhosted.org/packages/fe/02/f408c804e0ee78c367dcea0a01aedde4f1712af93b8b6e60df981e0228c7/black-24.10.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:17374989640fbca88b6a448129cd1745c5eb8d9547b464f281b251dd00155ccd", size = 1622516 }, { url = "https://files.pythonhosted.org/packages/f8/b9/9b706ed2f55bfb28b436225a9c57da35990c9005b90b8c91f03924454ad7/black-24.10.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:63f626344343083322233f175aaf372d326de8436f5928c042639a4afbbf1d3f", size = 1456181 }, { url = "https://files.pythonhosted.org/packages/0a/1c/314d7f17434a5375682ad097f6f4cc0e3f414f3c95a9b1bb4df14a0f11f9/black-24.10.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ccfa1d0cb6200857f1923b602f978386a3a2758a65b52e0950299ea014be6800", size = 1752801 }, { url = "https://files.pythonhosted.org/packages/39/a7/20e5cd9237d28ad0b31438de5d9f01c8b99814576f4c0cda1edd62caf4b0/black-24.10.0-cp39-cp39-win_amd64.whl", hash = "sha256:2cd9c95431d94adc56600710f8813ee27eea544dd118d45896bb734e9d7a0dc7", size = 1413626 }, { url = "https://files.pythonhosted.org/packages/8d/a7/4b27c50537ebca8bec139b872861f9d2bf501c5ec51fcf897cb924d9e264/black-24.10.0-py3-none-any.whl", hash = "sha256:3bb2b7a1f7b685f85b11fed1ef10f8a9148bceb49853e47a294a3dd963c1dd7d", size = 206898 }, ] [[package]] name = "click" version = "8.1.8" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "colorama", marker = "platform_system == 'Windows'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/b9/2e/0090cbf739cee7d23781ad4b89a9894a41538e4fcf4c31dcdd705b78eb8b/click-8.1.8.tar.gz", hash = "sha256:ed53c9d8990d83c2a27deae68e4ee337473f6330c040a31d4225c9574d16096a", size = 226593 } wheels = [ { url = "https://files.pythonhosted.org/packages/7e/d4/7ebdbd03970677812aac39c869717059dbb71a4cfc033ca6e5221787892c/click-8.1.8-py3-none-any.whl", hash = "sha256:63c132bbbed01578a06712a2d1f497bb62d9c1c0d329b7903a866228027263b2", size = 98188 }, ] [[package]] name = "colorama" version = "0.4.6" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/d8/53/6f443c9a4a8358a93a6792e2acffb9d9d5cb0a5cfd8802644b7b1c9a02e4/colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44", size = 27697 } wheels = [ { url = "https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6", size = 25335 }, ] [[package]] name = "example-isort-formatting-plugin" version = "0.1.1" source = { editable = "." } dependencies = [ { name = "black" }, { name = "isort" }, ] [package.metadata] requires-dist = [ { name = "black", specifier = ">=24.3.0" }, { name = "isort", specifier = ">=5.13.2" }, ] [[package]] name = "isort" version = "5.13.2" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/87/f9/c1eb8635a24e87ade2efce21e3ce8cd6b8630bb685ddc9cdaca1349b2eb5/isort-5.13.2.tar.gz", hash = "sha256:48fdfcb9face5d58a4f6dde2e72a1fb8dcaf8ab26f95ab49fab84c2ddefb0109", size = 175303 } wheels = [ { url = "https://files.pythonhosted.org/packages/d1/b3/8def84f539e7d2289a02f0524b944b15d7c75dab7628bedf1c4f0992029c/isort-5.13.2-py3-none-any.whl", hash = "sha256:8ca5e72a8d85860d5a3fa69b8745237f2939afe12dbf656afbcb47fe72d947a6", size = 92310 }, ] [[package]] name = "mypy-extensions" version = "1.0.0" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/98/a4/1ab47638b92648243faf97a5aeb6ea83059cc3624972ab6b8d2316078d3f/mypy_extensions-1.0.0.tar.gz", hash = "sha256:75dbf8955dc00442a438fc4d0666508a9a97b6bd41aa2f0ffe9d2f2725af0782", size = 4433 } wheels = [ { url = "https://files.pythonhosted.org/packages/2a/e2/5d3f6ada4297caebe1a2add3b126fe800c96f56dbe5d1988a2cbe0b267aa/mypy_extensions-1.0.0-py3-none-any.whl", hash = "sha256:4392f6c0eb8a5668a69e23d168ffa70f0be9ccfd32b5cc2d26a34ae5b844552d", size = 4695 }, ] [[package]] name = "packaging" version = "24.2" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/d0/63/68dbb6eb2de9cb10ee4c9c14a0148804425e13c4fb20d61cce69f53106da/packaging-24.2.tar.gz", hash = "sha256:c228a6dc5e932d346bc5739379109d49e8853dd8223571c7c5b55260edc0b97f", size = 163950 } wheels = [ { url = "https://files.pythonhosted.org/packages/88/ef/eb23f262cca3c0c4eb7ab1933c3b1f03d021f2c48f54763065b6f0e321be/packaging-24.2-py3-none-any.whl", hash = "sha256:09abb1bccd265c01f4a3aa3f7a7db064b36514d2cba19a2f694fe6150451a759", size = 65451 }, ] [[package]] name = "pathspec" version = "0.12.1" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/ca/bc/f35b8446f4531a7cb215605d100cd88b7ac6f44ab3fc94870c120ab3adbf/pathspec-0.12.1.tar.gz", hash = "sha256:a482d51503a1ab33b1c67a6c3813a26953dbdc71c31dacaef9a838c4e29f5712", size = 51043 } wheels = [ { url = "https://files.pythonhosted.org/packages/cc/20/ff623b09d963f88bfde16306a54e12ee5ea43e9b597108672ff3a408aad6/pathspec-0.12.1-py3-none-any.whl", hash = "sha256:a0d503e138a4c123b27490a4f7beda6a01c6f288df0e4a8b79c7eb0dc7b4cc08", size = 31191 }, ] [[package]] name = "platformdirs" version = "4.3.6" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/13/fc/128cc9cb8f03208bdbf93d3aa862e16d376844a14f9a0ce5cf4507372de4/platformdirs-4.3.6.tar.gz", hash = "sha256:357fb2acbc885b0419afd3ce3ed34564c13c9b95c89360cd9563f73aa5e2b907", size = 21302 } wheels = [ { url = "https://files.pythonhosted.org/packages/3c/a6/bc1012356d8ece4d66dd75c4b9fc6c1f6650ddd5991e421177d9f8f671be/platformdirs-4.3.6-py3-none-any.whl", hash = "sha256:73e575e1408ab8103900836b97580d5307456908a03e92031bab39e4554cc3fb", size = 18439 }, ] [[package]] name = "tomli" version = "2.2.1" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/18/87/302344fed471e44a87289cf4967697d07e532f2421fdaf868a303cbae4ff/tomli-2.2.1.tar.gz", hash = "sha256:cd45e1dc79c835ce60f7404ec8119f2eb06d38b1deba146f07ced3bbc44505ff", size = 17175 } wheels = [ { url = "https://files.pythonhosted.org/packages/43/ca/75707e6efa2b37c77dadb324ae7d9571cb424e61ea73fad7c56c2d14527f/tomli-2.2.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:678e4fa69e4575eb77d103de3df8a895e1591b48e740211bd1067378c69e8249", size = 131077 }, { url = "https://files.pythonhosted.org/packages/c7/16/51ae563a8615d472fdbffc43a3f3d46588c264ac4f024f63f01283becfbb/tomli-2.2.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:023aa114dd824ade0100497eb2318602af309e5a55595f76b626d6d9f3b7b0a6", size = 123429 }, { url = "https://files.pythonhosted.org/packages/f1/dd/4f6cd1e7b160041db83c694abc78e100473c15d54620083dbd5aae7b990e/tomli-2.2.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ece47d672db52ac607a3d9599a9d48dcb2f2f735c6c2d1f34130085bb12b112a", size = 226067 }, { url = "https://files.pythonhosted.org/packages/a9/6b/c54ede5dc70d648cc6361eaf429304b02f2871a345bbdd51e993d6cdf550/tomli-2.2.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6972ca9c9cc9f0acaa56a8ca1ff51e7af152a9f87fb64623e31d5c83700080ee", size = 236030 }, { url = "https://files.pythonhosted.org/packages/1f/47/999514fa49cfaf7a92c805a86c3c43f4215621855d151b61c602abb38091/tomli-2.2.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c954d2250168d28797dd4e3ac5cf812a406cd5a92674ee4c8f123c889786aa8e", size = 240898 }, { url = "https://files.pythonhosted.org/packages/73/41/0a01279a7ae09ee1573b423318e7934674ce06eb33f50936655071d81a24/tomli-2.2.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:8dd28b3e155b80f4d54beb40a441d366adcfe740969820caf156c019fb5c7ec4", size = 229894 }, { url = "https://files.pythonhosted.org/packages/55/18/5d8bc5b0a0362311ce4d18830a5d28943667599a60d20118074ea1b01bb7/tomli-2.2.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:e59e304978767a54663af13c07b3d1af22ddee3bb2fb0618ca1593e4f593a106", size = 245319 }, { url = "https://files.pythonhosted.org/packages/92/a3/7ade0576d17f3cdf5ff44d61390d4b3febb8a9fc2b480c75c47ea048c646/tomli-2.2.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:33580bccab0338d00994d7f16f4c4ec25b776af3ffaac1ed74e0b3fc95e885a8", size = 238273 }, { url = "https://files.pythonhosted.org/packages/72/6f/fa64ef058ac1446a1e51110c375339b3ec6be245af9d14c87c4a6412dd32/tomli-2.2.1-cp311-cp311-win32.whl", hash = "sha256:465af0e0875402f1d226519c9904f37254b3045fc5084697cefb9bdde1ff99ff", size = 98310 }, { url = "https://files.pythonhosted.org/packages/6a/1c/4a2dcde4a51b81be3530565e92eda625d94dafb46dbeb15069df4caffc34/tomli-2.2.1-cp311-cp311-win_amd64.whl", hash = "sha256:2d0f2fdd22b02c6d81637a3c95f8cd77f995846af7414c5c4b8d0545afa1bc4b", size = 108309 }, { url = "https://files.pythonhosted.org/packages/52/e1/f8af4c2fcde17500422858155aeb0d7e93477a0d59a98e56cbfe75070fd0/tomli-2.2.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:4a8f6e44de52d5e6c657c9fe83b562f5f4256d8ebbfe4ff922c495620a7f6cea", size = 132762 }, { url = "https://files.pythonhosted.org/packages/03/b8/152c68bb84fc00396b83e7bbddd5ec0bd3dd409db4195e2a9b3e398ad2e3/tomli-2.2.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:8d57ca8095a641b8237d5b079147646153d22552f1c637fd3ba7f4b0b29167a8", size = 123453 }, { url = "https://files.pythonhosted.org/packages/c8/d6/fc9267af9166f79ac528ff7e8c55c8181ded34eb4b0e93daa767b8841573/tomli-2.2.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4e340144ad7ae1533cb897d406382b4b6fede8890a03738ff1683af800d54192", size = 233486 }, { url = "https://files.pythonhosted.org/packages/5c/51/51c3f2884d7bab89af25f678447ea7d297b53b5a3b5730a7cb2ef6069f07/tomli-2.2.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:db2b95f9de79181805df90bedc5a5ab4c165e6ec3fe99f970d0e302f384ad222", size = 242349 }, { url = "https://files.pythonhosted.org/packages/ab/df/bfa89627d13a5cc22402e441e8a931ef2108403db390ff3345c05253935e/tomli-2.2.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:40741994320b232529c802f8bc86da4e1aa9f413db394617b9a256ae0f9a7f77", size = 252159 }, { url = "https://files.pythonhosted.org/packages/9e/6e/fa2b916dced65763a5168c6ccb91066f7639bdc88b48adda990db10c8c0b/tomli-2.2.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:400e720fe168c0f8521520190686ef8ef033fb19fc493da09779e592861b78c6", size = 237243 }, { url = "https://files.pythonhosted.org/packages/b4/04/885d3b1f650e1153cbb93a6a9782c58a972b94ea4483ae4ac5cedd5e4a09/tomli-2.2.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:02abe224de6ae62c19f090f68da4e27b10af2b93213d36cf44e6e1c5abd19fdd", size = 259645 }, { url = "https://files.pythonhosted.org/packages/9c/de/6b432d66e986e501586da298e28ebeefd3edc2c780f3ad73d22566034239/tomli-2.2.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:b82ebccc8c8a36f2094e969560a1b836758481f3dc360ce9a3277c65f374285e", size = 244584 }, { url = "https://files.pythonhosted.org/packages/1c/9a/47c0449b98e6e7d1be6cbac02f93dd79003234ddc4aaab6ba07a9a7482e2/tomli-2.2.1-cp312-cp312-win32.whl", hash = "sha256:889f80ef92701b9dbb224e49ec87c645ce5df3fa2cc548664eb8a25e03127a98", size = 98875 }, { url = "https://files.pythonhosted.org/packages/ef/60/9b9638f081c6f1261e2688bd487625cd1e660d0a85bd469e91d8db969734/tomli-2.2.1-cp312-cp312-win_amd64.whl", hash = "sha256:7fc04e92e1d624a4a63c76474610238576942d6b8950a2d7f908a340494e67e4", size = 109418 }, { url = "https://files.pythonhosted.org/packages/04/90/2ee5f2e0362cb8a0b6499dc44f4d7d48f8fff06d28ba46e6f1eaa61a1388/tomli-2.2.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:f4039b9cbc3048b2416cc57ab3bda989a6fcf9b36cf8937f01a6e731b64f80d7", size = 132708 }, { url = "https://files.pythonhosted.org/packages/c0/ec/46b4108816de6b385141f082ba99e315501ccd0a2ea23db4a100dd3990ea/tomli-2.2.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:286f0ca2ffeeb5b9bd4fcc8d6c330534323ec51b2f52da063b11c502da16f30c", size = 123582 }, { url = "https://files.pythonhosted.org/packages/a0/bd/b470466d0137b37b68d24556c38a0cc819e8febe392d5b199dcd7f578365/tomli-2.2.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a92ef1a44547e894e2a17d24e7557a5e85a9e1d0048b0b5e7541f76c5032cb13", size = 232543 }, { url = "https://files.pythonhosted.org/packages/d9/e5/82e80ff3b751373f7cead2815bcbe2d51c895b3c990686741a8e56ec42ab/tomli-2.2.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9316dc65bed1684c9a98ee68759ceaed29d229e985297003e494aa825ebb0281", size = 241691 }, { url = "https://files.pythonhosted.org/packages/05/7e/2a110bc2713557d6a1bfb06af23dd01e7dde52b6ee7dadc589868f9abfac/tomli-2.2.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e85e99945e688e32d5a35c1ff38ed0b3f41f43fad8df0bdf79f72b2ba7bc5272", size = 251170 }, { url = "https://files.pythonhosted.org/packages/64/7b/22d713946efe00e0adbcdfd6d1aa119ae03fd0b60ebed51ebb3fa9f5a2e5/tomli-2.2.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:ac065718db92ca818f8d6141b5f66369833d4a80a9d74435a268c52bdfa73140", size = 236530 }, { url = "https://files.pythonhosted.org/packages/38/31/3a76f67da4b0cf37b742ca76beaf819dca0ebef26d78fc794a576e08accf/tomli-2.2.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:d920f33822747519673ee656a4b6ac33e382eca9d331c87770faa3eef562aeb2", size = 258666 }, { url = "https://files.pythonhosted.org/packages/07/10/5af1293da642aded87e8a988753945d0cf7e00a9452d3911dd3bb354c9e2/tomli-2.2.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:a198f10c4d1b1375d7687bc25294306e551bf1abfa4eace6650070a5c1ae2744", size = 243954 }, { url = "https://files.pythonhosted.org/packages/5b/b9/1ed31d167be802da0fc95020d04cd27b7d7065cc6fbefdd2f9186f60d7bd/tomli-2.2.1-cp313-cp313-win32.whl", hash = "sha256:d3f5614314d758649ab2ab3a62d4f2004c825922f9e370b29416484086b264ec", size = 98724 }, { url = "https://files.pythonhosted.org/packages/c7/32/b0963458706accd9afcfeb867c0f9175a741bf7b19cd424230714d722198/tomli-2.2.1-cp313-cp313-win_amd64.whl", hash = "sha256:a38aa0308e754b0e3c67e344754dff64999ff9b513e691d0e786265c93583c69", size = 109383 }, { url = "https://files.pythonhosted.org/packages/6e/c2/61d3e0f47e2b74ef40a68b9e6ad5984f6241a942f7cd3bbfbdbd03861ea9/tomli-2.2.1-py3-none-any.whl", hash = "sha256:cb55c73c5f4408779d0cf3eef9f762b9c9f147a77de7b258bef0a5628adc85cc", size = 14257 }, ] [[package]] name = "typing-extensions" version = "4.12.2" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/df/db/f35a00659bc03fec321ba8bce9420de607a1d37f8342eee1863174c69557/typing_extensions-4.12.2.tar.gz", hash = "sha256:1a7ead55c7e559dd4dee8856e3a88b41225abfe1ce8df57b7c13915fe121ffb8", size = 85321 } wheels = [ { url = "https://files.pythonhosted.org/packages/26/9f/ad63fc0248c5379346306f8668cda6e2e2e9c95e01216d2b8ffd9ff037d0/typing_extensions-4.12.2-py3-none-any.whl", hash = "sha256:04e5ca0351e0f3f85c6853954072df659d0d13fac324d0072316b67d7794700d", size = 37438 }, ] isort-6.0.1/example_isort_sorting_plugin/example_isort_sorting_plugin.py0000644000000000000000000000026613615410400024150 0ustar00from natsort import natsorted def natural_plus(*args, **kwargs) -> str: """An even more natural sorting order for isort using natsort.""" return natsorted(*args, **kwargs) isort-6.0.1/example_isort_sorting_plugin/pyproject.toml0000644000000000000000000000112313615410400020505 0ustar00[project] name = "example_isort_sorting_plugin" version = "0.1.0" description = "An example plugin that modifies isorts sorting order to provide an even more natural sort by utilizing natsort." authors = [{name = "Timothy Crosley", email = "timothy.crosley@gmail.com"}, {name = "staticdev", email = "staticdev-support@proton.me"}] license = "MIT" requires-python = ">=3.9.0" dependencies = [ "natsort>=7.1.1" ] [project.entry-points."isort.sort_function"] natural_plus = "example_isort_sorting_plugin:natural_plus" [build-system] requires = ["hatchling"] build-backend = "hatchling.build" isort-6.0.1/example_isort_sorting_plugin/uv.lock0000644000000000000000000000154613615410400017106 0ustar00version = 1 requires-python = ">=3.9.0" [[package]] name = "example-isort-sorting-plugin" version = "0.1.0" source = { editable = "." } dependencies = [ { name = "natsort" }, ] [package.metadata] requires-dist = [{ name = "natsort", specifier = ">=7.1.1" }] [[package]] name = "natsort" version = "8.4.0" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/e2/a9/a0c57aee75f77794adaf35322f8b6404cbd0f89ad45c87197a937764b7d0/natsort-8.4.0.tar.gz", hash = "sha256:45312c4a0e5507593da193dedd04abb1469253b601ecaf63445ad80f0a1ea581", size = 76575 } wheels = [ { url = "https://files.pythonhosted.org/packages/ef/82/7a9d0550484a62c6da82858ee9419f3dd1ccc9aa1c26a1e43da3ecd20b0d/natsort-8.4.0-py3-none-any.whl", hash = "sha256:4732914fb471f56b5cce04d7bae6f164a592c7712e1c85f9ef585e197299521c", size = 38268 }, ] isort-6.0.1/example_shared_isort_profile/example_shared_isort_profile.py0000644000000000000000000000023513615410400024012 0ustar00PROFILE = { "multi_line_output": 3, "include_trailing_comma": True, "force_grid_wrap": 0, "use_parentheses": True, "line_length": 100, } isort-6.0.1/example_shared_isort_profile/pyproject.toml0000644000000000000000000000071413615410400020435 0ustar00[project] name = "example_shared_isort_profile" version = "0.1.0" description = "An example shared isort profile" authors = [{name = "Timothy Crosley", email = "timothy.crosley@gmail.com"}, {name = "staticdev", email = "staticdev-support@proton.me"}] license = "MIT" requires-python = ">=3.9.0" [project.entry-points."isort.profiles"] example = "example_shared_isort_profile:PROFILE" [build-system] requires = ["hatchling"] build-backend = "hatchling.build" isort-6.0.1/example_shared_isort_profile/uv.lock0000644000000000000000000000021113615410400017015 0ustar00version = 1 requires-python = ">=3.9.0" [[package]] name = "example-shared-isort-profile" version = "0.1.0" source = { editable = "." } isort-6.0.1/isort/__init__.py0000644000000000000000000000155013615410400013050 0ustar00"""Defines the public isort interface""" __all__ = ( "Config", "ImportKey", "__version__", "check_code", "check_file", "check_stream", "code", "file", "find_imports_in_code", "find_imports_in_file", "find_imports_in_paths", "find_imports_in_stream", "place_module", "place_module_with_reason", "settings", "stream", ) from . import settings from ._version import __version__ from .api import ImportKey from .api import check_code_string as check_code from .api import ( check_file, check_stream, find_imports_in_code, find_imports_in_file, find_imports_in_paths, find_imports_in_stream, place_module, place_module_with_reason, ) from .api import sort_code_string as code from .api import sort_file as file from .api import sort_stream as stream from .settings import Config isort-6.0.1/isort/__main__.py0000644000000000000000000000004413615410400013026 0ustar00from isort.main import main main() isort-6.0.1/isort/_version.py0000644000000000000000000000011013615410400013124 0ustar00from importlib import metadata __version__ = metadata.version("isort") isort-6.0.1/isort/api.py0000644000000000000000000006350113615410400012066 0ustar00__all__ = ( "ImportKey", "check_code_string", "check_file", "check_stream", "find_imports_in_code", "find_imports_in_file", "find_imports_in_paths", "find_imports_in_stream", "place_module", "place_module_with_reason", "sort_code_string", "sort_file", "sort_stream", ) import contextlib import shutil import sys from enum import Enum from io import StringIO from itertools import chain from pathlib import Path from typing import Any, Iterator, Optional, Set, TextIO, Union, cast from warnings import warn from isort import core from . import files, identify, io from .exceptions import ( ExistingSyntaxErrors, FileSkipComment, FileSkipSetting, IntroducedSyntaxErrors, ) from .format import ask_whether_to_apply_changes_to_file, create_terminal_printer, show_unified_diff from .io import Empty, File from .place import module as place_module # noqa: F401 from .place import module_with_reason as place_module_with_reason # noqa: F401 from .settings import CYTHON_EXTENSIONS, DEFAULT_CONFIG, Config class ImportKey(Enum): """Defines how to key an individual import, generally for deduping. Import keys are defined from less to more specific: from x.y import z as a ______| | | | | | | | PACKAGE | | | ________| | | | | | MODULE | | _________________| | | | ATTRIBUTE | ______________________| | ALIAS """ PACKAGE = 1 MODULE = 2 ATTRIBUTE = 3 ALIAS = 4 def sort_code_string( code: str, extension: Optional[str] = None, config: Config = DEFAULT_CONFIG, file_path: Optional[Path] = None, disregard_skip: bool = False, show_diff: Union[bool, TextIO] = False, **config_kwargs: Any, ) -> str: """Sorts any imports within the provided code string, returning a new string with them sorted. - **code**: The string of code with imports that need to be sorted. - **extension**: The file extension that contains imports. Defaults to filename extension or py. - **config**: The config object to use when sorting imports. - **file_path**: The disk location where the code string was pulled from. - **disregard_skip**: set to `True` if you want to ignore a skip set in config for this file. - **show_diff**: If `True` the changes that need to be done will be printed to stdout, if a TextIO stream is provided results will be written to it, otherwise no diff will be computed. - ****config_kwargs**: Any config modifications. """ input_stream = StringIO(code) output_stream = StringIO() config = _config(path=file_path, config=config, **config_kwargs) sort_stream( input_stream, output_stream, extension=extension, config=config, file_path=file_path, disregard_skip=disregard_skip, show_diff=show_diff, ) output_stream.seek(0) return output_stream.read() def check_code_string( code: str, show_diff: Union[bool, TextIO] = False, extension: Optional[str] = None, config: Config = DEFAULT_CONFIG, file_path: Optional[Path] = None, disregard_skip: bool = False, **config_kwargs: Any, ) -> bool: """Checks the order, format, and categorization of imports within the provided code string. Returns `True` if everything is correct, otherwise `False`. - **code**: The string of code with imports that need to be sorted. - **show_diff**: If `True` the changes that need to be done will be printed to stdout, if a TextIO stream is provided results will be written to it, otherwise no diff will be computed. - **extension**: The file extension that contains imports. Defaults to filename extension or py. - **config**: The config object to use when sorting imports. - **file_path**: The disk location where the code string was pulled from. - **disregard_skip**: set to `True` if you want to ignore a skip set in config for this file. - ****config_kwargs**: Any config modifications. """ config = _config(path=file_path, config=config, **config_kwargs) return check_stream( StringIO(code), show_diff=show_diff, extension=extension, config=config, file_path=file_path, disregard_skip=disregard_skip, ) def sort_stream( input_stream: TextIO, output_stream: TextIO, extension: Optional[str] = None, config: Config = DEFAULT_CONFIG, file_path: Optional[Path] = None, disregard_skip: bool = False, show_diff: Union[bool, TextIO] = False, raise_on_skip: bool = True, **config_kwargs: Any, ) -> bool: """Sorts any imports within the provided code stream, outputs to the provided output stream. Returns `True` if anything is modified from the original input stream, otherwise `False`. - **input_stream**: The stream of code with imports that need to be sorted. - **output_stream**: The stream where sorted imports should be written to. - **extension**: The file extension that contains imports. Defaults to filename extension or py. - **config**: The config object to use when sorting imports. - **file_path**: The disk location where the code string was pulled from. - **disregard_skip**: set to `True` if you want to ignore a skip set in config for this file. - **show_diff**: If `True` the changes that need to be done will be printed to stdout, if a TextIO stream is provided results will be written to it, otherwise no diff will be computed. - ****config_kwargs**: Any config modifications. """ extension = extension or (file_path and file_path.suffix.lstrip(".")) or "py" if show_diff: _output_stream = StringIO() _input_stream = StringIO(input_stream.read()) changed = sort_stream( input_stream=_input_stream, output_stream=_output_stream, extension=extension, config=config, file_path=file_path, disregard_skip=disregard_skip, raise_on_skip=raise_on_skip, **config_kwargs, ) _output_stream.seek(0) _input_stream.seek(0) show_unified_diff( file_input=_input_stream.read(), file_output=_output_stream.read(), file_path=file_path, output=output_stream if show_diff is True else show_diff, color_output=config.color_output, ) return changed config = _config(path=file_path, config=config, **config_kwargs) content_source = str(file_path or "Passed in content") if not disregard_skip and file_path and config.is_skipped(file_path): raise FileSkipSetting(content_source) _internal_output = output_stream if config.atomic: try: file_content = input_stream.read() compile(file_content, content_source, "exec", flags=0, dont_inherit=True) except SyntaxError: if extension not in CYTHON_EXTENSIONS: raise ExistingSyntaxErrors(content_source) if config.verbose: warn( f"{content_source} Python AST errors found but ignored due to Cython extension", stacklevel=2, ) input_stream = StringIO(file_content) if not output_stream.readable(): _internal_output = StringIO() try: changed = core.process( input_stream, _internal_output, extension=extension, config=config, raise_on_skip=raise_on_skip, ) except FileSkipComment: raise FileSkipComment(content_source) if config.atomic: _internal_output.seek(0) try: compile(_internal_output.read(), content_source, "exec", flags=0, dont_inherit=True) _internal_output.seek(0) except SyntaxError: # pragma: no cover if extension not in CYTHON_EXTENSIONS: raise IntroducedSyntaxErrors(content_source) if config.verbose: warn( f"{content_source} Python AST errors found but ignored due to Cython extension", stacklevel=2, ) if _internal_output != output_stream: output_stream.write(_internal_output.read()) return changed def check_stream( input_stream: TextIO, show_diff: Union[bool, TextIO] = False, extension: Optional[str] = None, config: Config = DEFAULT_CONFIG, file_path: Optional[Path] = None, disregard_skip: bool = False, **config_kwargs: Any, ) -> bool: """Checks any imports within the provided code stream, returning `False` if any unsorted or incorrectly imports are found or `True` if no problems are identified. - **input_stream**: The stream of code with imports that need to be sorted. - **show_diff**: If `True` the changes that need to be done will be printed to stdout, if a TextIO stream is provided results will be written to it, otherwise no diff will be computed. - **extension**: The file extension that contains imports. Defaults to filename extension or py. - **config**: The config object to use when sorting imports. - **file_path**: The disk location where the code string was pulled from. - **disregard_skip**: set to `True` if you want to ignore a skip set in config for this file. - ****config_kwargs**: Any config modifications. """ config = _config(path=file_path, config=config, **config_kwargs) if show_diff: input_stream = StringIO(input_stream.read()) changed: bool = sort_stream( input_stream=input_stream, output_stream=Empty, extension=extension, config=config, file_path=file_path, disregard_skip=disregard_skip, ) printer = create_terminal_printer( color=config.color_output, error=config.format_error, success=config.format_success ) if not changed: if config.verbose and not config.only_modified: printer.success(f"{file_path or ''} Everything Looks Good!") return True printer.error(f"{file_path or ''} Imports are incorrectly sorted and/or formatted.") if show_diff: output_stream = StringIO() input_stream.seek(0) file_contents = input_stream.read() sort_stream( input_stream=StringIO(file_contents), output_stream=output_stream, extension=extension, config=config, file_path=file_path, disregard_skip=disregard_skip, ) output_stream.seek(0) show_unified_diff( file_input=file_contents, file_output=output_stream.read(), file_path=file_path, output=None if show_diff is True else show_diff, color_output=config.color_output, ) return False def check_file( filename: Union[str, Path], show_diff: Union[bool, TextIO] = False, config: Config = DEFAULT_CONFIG, file_path: Optional[Path] = None, disregard_skip: bool = True, extension: Optional[str] = None, **config_kwargs: Any, ) -> bool: """Checks any imports within the provided file, returning `False` if any unsorted or incorrectly imports are found or `True` if no problems are identified. - **filename**: The name or Path of the file to check. - **show_diff**: If `True` the changes that need to be done will be printed to stdout, if a TextIO stream is provided results will be written to it, otherwise no diff will be computed. - **config**: The config object to use when sorting imports. - **file_path**: The disk location where the code string was pulled from. - **disregard_skip**: set to `True` if you want to ignore a skip set in config for this file. - **extension**: The file extension that contains imports. Defaults to filename extension or py. - ****config_kwargs**: Any config modifications. """ file_config: Config = config if "config_trie" in config_kwargs: config_trie = config_kwargs.pop("config_trie", None) if config_trie: config_info = config_trie.search(filename) if config.verbose: print(f"{config_info[0]} used for file {filename}") file_config = Config(**config_info[1]) with io.File.read(filename) as source_file: return check_stream( source_file.stream, show_diff=show_diff, extension=extension, config=file_config, file_path=file_path or source_file.path, disregard_skip=disregard_skip, **config_kwargs, ) def _tmp_file(source_file: File) -> Path: return source_file.path.with_suffix(source_file.path.suffix + ".isorted") @contextlib.contextmanager def _in_memory_output_stream_context() -> Iterator[TextIO]: yield StringIO(newline=None) @contextlib.contextmanager def _file_output_stream_context(filename: Union[str, Path], source_file: File) -> Iterator[TextIO]: tmp_file = _tmp_file(source_file) with tmp_file.open("w+", encoding=source_file.encoding, newline="") as output_stream: shutil.copymode(filename, tmp_file) yield output_stream # Ignore DeepSource cyclomatic complexity check for this function. It is one # the main entrypoints so sort of expected to be complex. # skipcq: PY-R1000 def sort_file( filename: Union[str, Path], extension: Optional[str] = None, config: Config = DEFAULT_CONFIG, file_path: Optional[Path] = None, disregard_skip: bool = True, ask_to_apply: bool = False, show_diff: Union[bool, TextIO] = False, write_to_stdout: bool = False, output: Optional[TextIO] = None, **config_kwargs: Any, ) -> bool: """Sorts and formats any groups of imports imports within the provided file or Path. Returns `True` if the file has been changed, otherwise `False`. - **filename**: The name or Path of the file to format. - **extension**: The file extension that contains imports. Defaults to filename extension or py. - **config**: The config object to use when sorting imports. - **file_path**: The disk location where the code string was pulled from. - **disregard_skip**: set to `True` if you want to ignore a skip set in config for this file. - **ask_to_apply**: If `True`, prompt before applying any changes. - **show_diff**: If `True` the changes that need to be done will be printed to stdout, if a TextIO stream is provided results will be written to it, otherwise no diff will be computed. - **write_to_stdout**: If `True`, write to stdout instead of the input file. - **output**: If a TextIO is provided, results will be written there rather than replacing the original file content. - ****config_kwargs**: Any config modifications. """ file_config: Config = config if "config_trie" in config_kwargs: config_trie = config_kwargs.pop("config_trie", None) if config_trie: config_info = config_trie.search(filename) if config.verbose: print(f"{config_info[0]} used for file {filename}") file_config = Config(**config_info[1]) with io.File.read(filename) as source_file: actual_file_path = file_path or source_file.path config = _config(path=actual_file_path, config=file_config, **config_kwargs) changed: bool = False try: if write_to_stdout: changed = sort_stream( input_stream=source_file.stream, output_stream=sys.stdout, config=config, file_path=actual_file_path, disregard_skip=disregard_skip, extension=extension, ) else: if output is None: try: if config.overwrite_in_place: output_stream_context = _in_memory_output_stream_context() else: output_stream_context = _file_output_stream_context( filename, source_file ) with output_stream_context as output_stream: changed = sort_stream( input_stream=source_file.stream, output_stream=output_stream, config=config, file_path=actual_file_path, disregard_skip=disregard_skip, extension=extension, ) output_stream.seek(0) if changed: if show_diff or ask_to_apply: source_file.stream.seek(0) show_unified_diff( file_input=source_file.stream.read(), file_output=output_stream.read(), file_path=actual_file_path, output=( None if show_diff is True else cast(TextIO, show_diff) ), color_output=config.color_output, ) if show_diff or ( ask_to_apply and not ask_whether_to_apply_changes_to_file( str(source_file.path) ) ): return False source_file.stream.close() if config.overwrite_in_place: output_stream.seek(0) with source_file.path.open("w") as fs: shutil.copyfileobj(output_stream, fs) if changed: if not config.overwrite_in_place: tmp_file = _tmp_file(source_file) tmp_file.replace(source_file.path) if not config.quiet: print(f"Fixing {source_file.path}") finally: if not config.overwrite_in_place: # pragma: no branch tmp_file = _tmp_file(source_file) tmp_file.unlink(missing_ok=True) else: changed = sort_stream( input_stream=source_file.stream, output_stream=output, config=config, file_path=actual_file_path, disregard_skip=disregard_skip, extension=extension, ) if changed and show_diff: source_file.stream.seek(0) output.seek(0) show_unified_diff( file_input=source_file.stream.read(), file_output=output.read(), file_path=actual_file_path, output=None if show_diff is True else show_diff, color_output=config.color_output, ) source_file.stream.close() except ExistingSyntaxErrors: warn(f"{actual_file_path} unable to sort due to existing syntax errors", stacklevel=2) except IntroducedSyntaxErrors: # pragma: no cover warn( f"{actual_file_path} unable to sort as isort introduces new syntax errors", stacklevel=2, ) return changed def find_imports_in_code( code: str, config: Config = DEFAULT_CONFIG, file_path: Optional[Path] = None, unique: Union[bool, ImportKey] = False, top_only: bool = False, **config_kwargs: Any, ) -> Iterator[identify.Import]: """Finds and returns all imports within the provided code string. - **code**: The string of code with imports that need to be sorted. - **config**: The config object to use when sorting imports. - **file_path**: The disk location where the code string was pulled from. - **unique**: If True, only the first instance of an import is returned. - **top_only**: If True, only return imports that occur before the first function or class. - ****config_kwargs**: Any config modifications. """ yield from find_imports_in_stream( input_stream=StringIO(code), config=config, file_path=file_path, unique=unique, top_only=top_only, **config_kwargs, ) def find_imports_in_stream( input_stream: TextIO, config: Config = DEFAULT_CONFIG, file_path: Optional[Path] = None, unique: Union[bool, ImportKey] = False, top_only: bool = False, _seen: Optional[Set[str]] = None, **config_kwargs: Any, ) -> Iterator[identify.Import]: """Finds and returns all imports within the provided code stream. - **input_stream**: The stream of code with imports that need to be sorted. - **config**: The config object to use when sorting imports. - **file_path**: The disk location where the code string was pulled from. - **unique**: If True, only the first instance of an import is returned. - **top_only**: If True, only return imports that occur before the first function or class. - **_seen**: An optional set of imports already seen. Generally meant only for internal use. - ****config_kwargs**: Any config modifications. """ config = _config(config=config, **config_kwargs) identified_imports = identify.imports( input_stream, config=config, file_path=file_path, top_only=top_only ) if not unique: yield from identified_imports seen: Set[str] = set() if _seen is None else _seen for identified_import in identified_imports: if unique in (True, ImportKey.ALIAS): key = identified_import.statement() elif unique == ImportKey.ATTRIBUTE: key = f"{identified_import.module}.{identified_import.attribute}" elif unique == ImportKey.MODULE: key = identified_import.module elif unique == ImportKey.PACKAGE: # pragma: no branch # type checking ensures this key = identified_import.module.split(".")[0] if key and key not in seen: seen.add(key) yield identified_import def find_imports_in_file( filename: Union[str, Path], config: Config = DEFAULT_CONFIG, file_path: Optional[Path] = None, unique: Union[bool, ImportKey] = False, top_only: bool = False, **config_kwargs: Any, ) -> Iterator[identify.Import]: """Finds and returns all imports within the provided source file. - **filename**: The name or Path of the file to look for imports in. - **extension**: The file extension that contains imports. Defaults to filename extension or py. - **config**: The config object to use when sorting imports. - **file_path**: The disk location where the code string was pulled from. - **unique**: If True, only the first instance of an import is returned. - **top_only**: If True, only return imports that occur before the first function or class. - ****config_kwargs**: Any config modifications. """ try: with io.File.read(filename) as source_file: yield from find_imports_in_stream( input_stream=source_file.stream, config=config, file_path=file_path or source_file.path, unique=unique, top_only=top_only, **config_kwargs, ) except OSError as error: warn(f"Unable to parse file {filename} due to {error}", stacklevel=2) def find_imports_in_paths( paths: Iterator[Union[str, Path]], config: Config = DEFAULT_CONFIG, file_path: Optional[Path] = None, unique: Union[bool, ImportKey] = False, top_only: bool = False, **config_kwargs: Any, ) -> Iterator[identify.Import]: """Finds and returns all imports within the provided source paths. - **paths**: A collection of paths to recursively look for imports within. - **extension**: The file extension that contains imports. Defaults to filename extension or py. - **config**: The config object to use when sorting imports. - **file_path**: The disk location where the code string was pulled from. - **unique**: If True, only the first instance of an import is returned. - **top_only**: If True, only return imports that occur before the first function or class. - ****config_kwargs**: Any config modifications. """ config = _config(config=config, **config_kwargs) seen: Optional[Set[str]] = set() if unique else None yield from chain( *( find_imports_in_file( file_name, unique=unique, config=config, top_only=top_only, _seen=seen ) for file_name in files.find(map(str, paths), config, [], []) ) ) def _config( path: Optional[Path] = None, config: Config = DEFAULT_CONFIG, **config_kwargs: Any ) -> Config: if path and ( config is DEFAULT_CONFIG and "settings_path" not in config_kwargs and "settings_file" not in config_kwargs ): config_kwargs["settings_path"] = path if config_kwargs: if config is not DEFAULT_CONFIG: raise ValueError( "You can either specify custom configuration options using kwargs or " "passing in a Config object. Not Both!" ) config = Config(**config_kwargs) return config isort-6.0.1/isort/comments.py0000644000000000000000000000164513615410400013143 0ustar00from typing import List, Optional, Tuple def parse(line: str) -> Tuple[str, str]: """Parses import lines for comments and returns back the import statement and the associated comment. """ comment_start = line.find("#") if comment_start != -1: return (line[:comment_start], line[comment_start + 1 :].strip()) return (line, "") def add_to_line( comments: Optional[List[str]], original_string: str = "", removed: bool = False, comment_prefix: str = "", ) -> str: """Returns a string with comments added if removed is not set.""" if removed: return parse(original_string)[0] if not comments: return original_string unique_comments: List[str] = [] for comment in comments: if comment not in unique_comments: unique_comments.append(comment) return f"{parse(original_string)[0]}{comment_prefix} {'; '.join(unique_comments)}" isort-6.0.1/isort/core.py0000644000000000000000000005425713615410400012255 0ustar00import textwrap from io import StringIO from itertools import chain from typing import List, TextIO, Union import isort.literal from isort.settings import DEFAULT_CONFIG, Config from . import output, parse from .exceptions import ExistingSyntaxErrors, FileSkipComment from .format import format_natural, remove_whitespace from .settings import FILE_SKIP_COMMENTS CIMPORT_IDENTIFIERS = ("cimport ", "cimport*", "from.cimport") IMPORT_START_IDENTIFIERS = ("from ", "from.import", "import ", "import*", *CIMPORT_IDENTIFIERS) DOCSTRING_INDICATORS = ('"""', "'''") COMMENT_INDICATORS = (*DOCSTRING_INDICATORS, "'", '"', "#") CODE_SORT_COMMENTS = ( "# isort: list", "# isort: dict", "# isort: set", "# isort: unique-list", "# isort: tuple", "# isort: unique-tuple", "# isort: assignments", ) LITERAL_TYPE_MAPPING = {"(": "tuple", "[": "list", "{": "set"} # Ignore DeepSource cyclomatic complexity check for this function. # skipcq: PY-R1000 def process( input_stream: TextIO, output_stream: TextIO, extension: str = "py", raise_on_skip: bool = True, config: Config = DEFAULT_CONFIG, ) -> bool: """Parses stream identifying sections of contiguous imports and sorting them Code with unsorted imports is read from the provided `input_stream`, sorted and then outputted to the specified `output_stream`. - `input_stream`: Text stream with unsorted import sections. - `output_stream`: Text stream to output sorted inputs into. - `config`: Config settings to use when sorting imports. Defaults settings. - *Default*: `isort.settings.DEFAULT_CONFIG`. - `extension`: The file extension or file extension rules that should be used. - *Default*: `"py"`. - *Choices*: `["py", "pyi", "pyx"]`. Returns `True` if there were changes that needed to be made (errors present) from what was provided in the input_stream, otherwise `False`. """ line_separator: str = config.line_ending add_imports: List[str] = [format_natural(addition) for addition in config.add_imports] import_section: str = "" next_import_section: str = "" next_cimports: bool = False in_quote: str = "" was_in_quote: bool = False first_comment_index_start: int = -1 first_comment_index_end: int = -1 contains_imports: bool = False in_top_comment: bool = False first_import_section: bool = True indent: str = "" isort_off: bool = False skip_file: bool = False code_sorting: Union[bool, str] = False code_sorting_section: str = "" code_sorting_indent: str = "" cimports: bool = False made_changes: bool = False stripped_line: str = "" end_of_file: bool = False verbose_output: List[str] = [] lines_before: List[str] = [] is_reexport: bool = False reexport_rollback: int = 0 if config.float_to_top: new_input = "" current = "" isort_off = False for line in chain(input_stream, (None,)): if isort_off and line is not None: if line == "# isort: on\n": isort_off = False new_input += line elif line in ("# isort: split\n", "# isort: off\n", None) or str(line).endswith( "# isort: split\n" ): if line == "# isort: off\n": isort_off = True if current: if add_imports: add_line_separator = line_separator or "\n" current += add_line_separator + add_line_separator.join(add_imports) add_imports = [] parsed = parse.file_contents(current, config=config) verbose_output += parsed.verbose_output extra_space = "" while current and current[-1] == "\n": extra_space += "\n" current = current[:-1] extra_space = extra_space.replace("\n", "", 1) sorted_output = output.sorted_imports( parsed, config, extension, import_type="import" ) made_changes = made_changes or _has_changed( before=current, after=sorted_output, line_separator=parsed.line_separator, ignore_whitespace=config.ignore_whitespace, ) new_input += sorted_output new_input += extra_space current = "" new_input += line or "" else: current += line or "" input_stream = StringIO(new_input) for index, line in enumerate(chain(input_stream, (None,))): if line is None: if index == 0 and not config.force_adds: return False not_imports = True end_of_file = True line = "" if not line_separator: line_separator = "\n" if code_sorting and code_sorting_section: if is_reexport: output_stream.seek(output_stream.tell() - reexport_rollback) reexport_rollback = 0 sorted_code = textwrap.indent( isort.literal.assignment( code_sorting_section, str(code_sorting), extension, config=_indented_config(config, indent), ), code_sorting_indent, ) made_changes = made_changes or _has_changed( before=code_sorting_section, after=sorted_code, line_separator=line_separator, ignore_whitespace=config.ignore_whitespace, ) output_stream.write(sorted_code) if is_reexport: output_stream.truncate() else: stripped_line = line.strip() if stripped_line and not line_separator: line_separator = line[len(line.rstrip()) :].replace(" ", "").replace("\t", "") for file_skip_comment in FILE_SKIP_COMMENTS: if file_skip_comment in line: if raise_on_skip: raise FileSkipComment("Passed in content") isort_off = True skip_file = True if not in_quote: if stripped_line == "# isort: off": isort_off = True elif stripped_line.startswith("# isort: dont-add-imports"): add_imports = [] elif stripped_line.startswith("# isort: dont-add-import:"): import_not_to_add = stripped_line.split("# isort: dont-add-import:", 1)[ 1 ].strip() add_imports = [ import_to_add for import_to_add in add_imports if import_to_add != import_not_to_add ] if ( (index == 0 or (index in {1, 2} and not contains_imports)) and stripped_line.startswith("#") and stripped_line not in config.section_comments and stripped_line not in CODE_SORT_COMMENTS ): in_top_comment = True elif in_top_comment and ( not line.startswith("#") or stripped_line in config.section_comments or stripped_line in CODE_SORT_COMMENTS ): in_top_comment = False first_comment_index_end = index - 1 was_in_quote = bool(in_quote) if ((not stripped_line.startswith("#") or in_quote) and '"' in line) or "'" in line: char_index = 0 if first_comment_index_start == -1 and line.startswith(('"', "'")): first_comment_index_start = index while char_index < len(line): if line[char_index] == "\\": char_index += 1 elif in_quote: if line[char_index : char_index + len(in_quote)] == in_quote: in_quote = "" if first_comment_index_end < first_comment_index_start: first_comment_index_end = index elif line[char_index] in ("'", '"'): long_quote = line[char_index : char_index + 3] if long_quote in ('"""', "'''"): in_quote = long_quote char_index += 2 else: in_quote = line[char_index] elif line[char_index] == "#": break char_index += 1 not_imports = bool(in_quote) or was_in_quote or in_top_comment or isort_off if not (in_quote or was_in_quote or in_top_comment): if isort_off: if not skip_file and stripped_line == "# isort: on": isort_off = False elif stripped_line.endswith("# isort: split"): not_imports = True elif stripped_line in CODE_SORT_COMMENTS: code_sorting = stripped_line.split("isort: ")[1].strip() code_sorting_indent = line[: -len(line.lstrip())] not_imports = True elif config.sort_reexports and stripped_line.startswith("__all__"): _, rhs = stripped_line.split("=") code_sorting = LITERAL_TYPE_MAPPING.get(rhs.lstrip()[0], "tuple") code_sorting_indent = line[: -len(line.lstrip())] not_imports = True code_sorting_section += line reexport_rollback = len(line) is_reexport = True elif code_sorting: if not stripped_line: sorted_code = textwrap.indent( isort.literal.assignment( code_sorting_section, str(code_sorting), extension, config=_indented_config(config, indent), ), code_sorting_indent, ) made_changes = made_changes or _has_changed( before=code_sorting_section, after=sorted_code, line_separator=line_separator, ignore_whitespace=config.ignore_whitespace, ) if is_reexport: output_stream.seek(output_stream.tell() - reexport_rollback) reexport_rollback = 0 output_stream.write(sorted_code) if is_reexport: output_stream.truncate() not_imports = True code_sorting = False code_sorting_section = "" code_sorting_indent = "" is_reexport = False else: code_sorting_section += line line = "" elif ( stripped_line in config.section_comments or stripped_line in config.section_comments_end ): if import_section and not contains_imports: output_stream.write(import_section) import_section = line not_imports = False else: import_section += line indent = line[: -len(line.lstrip())] elif not (stripped_line or contains_imports): not_imports = True elif not stripped_line or ( stripped_line.startswith("#") and (not indent or indent + line.lstrip() == line) and not config.treat_all_comments_as_code and stripped_line not in config.treat_comments_as_code ): import_section += line elif stripped_line.startswith(IMPORT_START_IDENTIFIERS): new_indent = line[: -len(line.lstrip())] import_statement = line stripped_line = line.strip().split("#")[0] while stripped_line.endswith("\\") or ( "(" in stripped_line and ")" not in stripped_line ): if stripped_line.endswith("\\"): while stripped_line and stripped_line.endswith("\\"): line = input_stream.readline() stripped_line = line.strip().split("#")[0] import_statement += line else: while ")" not in stripped_line: line = input_stream.readline() if not line: # end of file without closing parenthesis raise ExistingSyntaxErrors("Parenthesis is not closed") stripped_line = line.strip().split("#")[0] import_statement += line if ( import_statement.lstrip().startswith("from") and "import" not in import_statement ): line = import_statement not_imports = True else: did_contain_imports = contains_imports contains_imports = True cimport_statement: bool = False if ( import_statement.lstrip().startswith(CIMPORT_IDENTIFIERS) or " cimport " in import_statement or " cimport*" in import_statement or " cimport(" in import_statement or ( ".cimport" in import_statement and "cython.cimports" not in import_statement ) # Allow pure python imports. See #2062 ): cimport_statement = True if cimport_statement != cimports or ( new_indent != indent and import_section and (not did_contain_imports or len(new_indent) < len(indent)) ): indent = new_indent if import_section: next_cimports = cimport_statement next_import_section = import_statement import_statement = "" not_imports = True line = "" else: cimports = cimport_statement else: if new_indent != indent: if import_section and did_contain_imports: import_statement = indent + import_statement.lstrip() else: indent = new_indent import_section += import_statement else: not_imports = True if not_imports: if not was_in_quote and config.lines_before_imports > -1: if line.strip() == "": lines_before += line continue if not import_section: output_stream.write("".join(lines_before)) lines_before = [] raw_import_section: str = import_section if ( add_imports and (stripped_line or end_of_file) and not config.append_only and not in_top_comment and not was_in_quote and not import_section and not line.lstrip().startswith(COMMENT_INDICATORS) and not (line.rstrip().endswith(DOCSTRING_INDICATORS) and "=" not in line) ): add_line_separator = line_separator or "\n" import_section = add_line_separator.join(add_imports) + add_line_separator if end_of_file and index != 0: output_stream.write(add_line_separator) contains_imports = True add_imports = [] if next_import_section and not import_section: # pragma: no cover raw_import_section = import_section = next_import_section next_import_section = "" if import_section: if add_imports and (contains_imports or not config.append_only) and not indent: import_section = ( line_separator.join(add_imports) + line_separator + import_section ) contains_imports = True add_imports = [] if not indent: import_section += line raw_import_section += line if not contains_imports: output_stream.write(import_section) else: leading_whitespace = import_section[: -len(import_section.lstrip())] trailing_whitespace = import_section[len(import_section.rstrip()) :] if first_import_section and not import_section.lstrip( line_separator ).startswith(COMMENT_INDICATORS): import_section = import_section.lstrip(line_separator) raw_import_section = raw_import_section.lstrip(line_separator) first_import_section = False if indent: import_section = "".join( line[len(indent) :] for line in import_section.splitlines(keepends=True) ) parsed_content = parse.file_contents(import_section, config=config) verbose_output += parsed_content.verbose_output sorted_import_section = output.sorted_imports( parsed_content, _indented_config(config, indent), extension, import_type="cimport" if cimports else "import", ) if not (import_section.strip() and not sorted_import_section): if indent: sorted_import_section = ( leading_whitespace + textwrap.indent(sorted_import_section, indent).strip() + trailing_whitespace ) made_changes = made_changes or _has_changed( before=raw_import_section, after=sorted_import_section, line_separator=line_separator, ignore_whitespace=config.ignore_whitespace, ) output_stream.write(sorted_import_section) if not line and not indent and next_import_section: output_stream.write(line_separator) if indent: output_stream.write(line) if not next_import_section: indent = "" if next_import_section: cimports = next_cimports contains_imports = True else: contains_imports = False import_section = next_import_section next_import_section = "" else: output_stream.write(line) not_imports = False if stripped_line and not in_quote and not import_section and not next_import_section: if stripped_line == "yield": while not stripped_line or stripped_line == "yield": new_line = input_stream.readline() if not new_line: break output_stream.write(new_line) stripped_line = new_line.strip().split("#")[0] if stripped_line.startswith(("raise", "yield")): while stripped_line.endswith("\\"): new_line = input_stream.readline() if not new_line: break output_stream.write(new_line) stripped_line = new_line.strip().split("#")[0] if made_changes and config.only_modified: for output_str in verbose_output: print(output_str) return made_changes def _indented_config(config: Config, indent: str) -> Config: if not indent: return config return Config( config=config, line_length=max(config.line_length - len(indent), 0), wrap_length=max(config.wrap_length - len(indent), 0), lines_after_imports=1, import_headings=config.import_headings if config.indented_import_headings else {}, import_footers=config.import_footers if config.indented_import_headings else {}, ) def _has_changed(before: str, after: str, line_separator: str, ignore_whitespace: bool) -> bool: if ignore_whitespace: return ( remove_whitespace(before, line_separator=line_separator).strip() != remove_whitespace(after, line_separator=line_separator).strip() ) return before.strip() != after.strip() isort-6.0.1/isort/exceptions.py0000644000000000000000000001562513615410400013502 0ustar00"""All isort specific exception classes should be defined here""" from functools import partial from pathlib import Path from typing import Any, Dict, List, Type, Union from .profiles import profiles class ISortError(Exception): """Base isort exception object from which all isort sourced exceptions should inherit""" def __reduce__(self): # type: ignore return (partial(type(self), **self.__dict__), ()) class InvalidSettingsPath(ISortError): """Raised when a settings path is provided that is neither a valid file or directory""" def __init__(self, settings_path: str): super().__init__( f"isort was told to use the settings_path: {settings_path} as the base directory or " "file that represents the starting point of config file discovery, but it does not " "exist." ) self.settings_path = settings_path class ExistingSyntaxErrors(ISortError): """Raised when isort is told to sort imports within code that has existing syntax errors""" def __init__(self, file_path: str): super().__init__( f"isort was told to sort imports within code that contains syntax errors: " f"{file_path}." ) self.file_path = file_path class IntroducedSyntaxErrors(ISortError): """Raised when isort has introduced a syntax error in the process of sorting imports""" def __init__(self, file_path: str): super().__init__( f"isort introduced syntax errors when attempting to sort the imports contained within " f"{file_path}." ) self.file_path = file_path class FileSkipped(ISortError): """Should be raised when a file is skipped for any reason""" def __init__(self, message: str, file_path: str): super().__init__(message) self.message = message self.file_path = file_path class FileSkipComment(FileSkipped): """Raised when an entire file is skipped due to a isort skip file comment""" def __init__(self, file_path: str, **kwargs: str): super().__init__( f"{file_path} contains a file skip comment and was skipped.", file_path=file_path ) class FileSkipSetting(FileSkipped): """Raised when an entire file is skipped due to provided isort settings""" def __init__(self, file_path: str, **kwargs: str): super().__init__( f"{file_path} was skipped as it's listed in 'skip' setting" " or matches a glob in 'skip_glob' setting", file_path=file_path, ) class ProfileDoesNotExist(ISortError): """Raised when a profile is set by the user that doesn't exist""" def __init__(self, profile: str): super().__init__( f"Specified profile of {profile} does not exist. " f"Available profiles: {','.join(profiles)}." ) self.profile = profile class SortingFunctionDoesNotExist(ISortError): """Raised when the specified sorting function isn't available""" def __init__(self, sort_order: str, available_sort_orders: List[str]): super().__init__( f"Specified sort_order of {sort_order} does not exist. " f"Available sort_orders: {','.join(available_sort_orders)}." ) self.sort_order = sort_order self.available_sort_orders = available_sort_orders class FormattingPluginDoesNotExist(ISortError): """Raised when a formatting plugin is set by the user that doesn't exist""" def __init__(self, formatter: str): super().__init__(f"Specified formatting plugin of {formatter} does not exist. ") self.formatter = formatter class LiteralParsingFailure(ISortError): """Raised when one of isorts literal sorting comments is used but isort can't parse the the given data structure. """ def __init__(self, code: str, original_error: Union[Exception, Type[Exception]]): super().__init__( f"isort failed to parse the given literal {code}. It's important to note " "that isort literal sorting only supports simple literals parsable by " f"ast.literal_eval which gave the exception of {original_error}." ) self.code = code self.original_error = original_error class LiteralSortTypeMismatch(ISortError): """Raised when an isort literal sorting comment is used, with a type that doesn't match the supplied data structure's type. """ def __init__(self, kind: type, expected_kind: type): super().__init__( f"isort was told to sort a literal of type {expected_kind} but was given " f"a literal of type {kind}." ) self.kind = kind self.expected_kind = expected_kind class AssignmentsFormatMismatch(ISortError): """Raised when isort is told to sort assignments but the format of the assignment section doesn't match isort's expectation. """ def __init__(self, code: str): super().__init__( "isort was told to sort a section of assignments, however the given code:\n\n" f"{code}\n\n" "Does not match isort's strict single line formatting requirement for assignment " "sorting:\n\n" "{variable_name} = {value}\n" "{variable_name2} = {value2}\n" "...\n\n" ) self.code = code class UnsupportedSettings(ISortError): """Raised when settings are passed into isort (either from config, CLI, or runtime) that it doesn't support. """ @staticmethod def _format_option(name: str, value: Any, source: str) -> str: return f"\t- {name} = {value} (source: '{source}')" def __init__(self, unsupported_settings: Dict[str, Dict[str, str]]): errors = "\n".join( self._format_option(name, **option) for name, option in unsupported_settings.items() ) super().__init__( "isort was provided settings that it doesn't support:\n\n" f"{errors}\n\n" "For a complete and up-to-date listing of supported settings see: " "https://pycqa.github.io/isort/docs/configuration/options.\n" ) self.unsupported_settings = unsupported_settings class UnsupportedEncoding(ISortError): """Raised when isort encounters an encoding error while trying to read a file""" def __init__(self, filename: Union[str, Path]): super().__init__(f"Unknown or unsupported encoding in {filename}") self.filename = filename class MissingSection(ISortError): """Raised when isort encounters an import that matches a section that is not defined""" def __init__(self, import_module: str, section: str): super().__init__( f"Found {import_module} import while parsing, but {section} was not included " "in the `sections` setting of your config. Please add it before continuing\n" "See https://pycqa.github.io/isort/#custom-sections-and-ordering " "for more info." ) isort-6.0.1/isort/files.py0000644000000000000000000000306513615410400012416 0ustar00import os from pathlib import Path from typing import Iterable, Iterator, List, Set from isort.settings import Config def find( paths: Iterable[str], config: Config, skipped: List[str], broken: List[str] ) -> Iterator[str]: """Fines and provides an iterator for all Python source files defined in paths.""" visited_dirs: Set[Path] = set() for path in paths: if os.path.isdir(path): for dirpath, dirnames, filenames in os.walk( path, topdown=True, followlinks=config.follow_links ): base_path = Path(dirpath) for dirname in list(dirnames): full_path = base_path / dirname resolved_path = full_path.resolve() if config.is_skipped(full_path): skipped.append(dirname) dirnames.remove(dirname) else: if resolved_path in visited_dirs: # pragma: no cover dirnames.remove(dirname) visited_dirs.add(resolved_path) for filename in filenames: filepath = os.path.join(dirpath, filename) if config.is_supported_filetype(filepath): if config.is_skipped(Path(os.path.abspath(filepath))): skipped.append(filename) else: yield filepath elif not os.path.exists(path): broken.append(path) else: yield path isort-6.0.1/isort/format.py0000644000000000000000000001255313615410400012606 0ustar00import re import sys from datetime import datetime from difflib import unified_diff from pathlib import Path from typing import Optional, TextIO try: import colorama except ImportError: colorama_unavailable = True else: colorama_unavailable = False ADDED_LINE_PATTERN = re.compile(r"\+[^+]") REMOVED_LINE_PATTERN = re.compile(r"-[^-]") def format_simplified(import_line: str) -> str: import_line = import_line.strip() if import_line.startswith("from "): import_line = import_line.replace("from ", "") import_line = import_line.replace(" import ", ".") elif import_line.startswith("import "): import_line = import_line.replace("import ", "") return import_line def format_natural(import_line: str) -> str: import_line = import_line.strip() if not import_line.startswith("from ") and not import_line.startswith("import "): if "." not in import_line: return f"import {import_line}" parts = import_line.split(".") end = parts.pop(-1) return f"from {'.'.join(parts)} import {end}" return import_line def show_unified_diff( *, file_input: str, file_output: str, file_path: Optional[Path], output: Optional[TextIO] = None, color_output: bool = False, ) -> None: """Shows a unified_diff for the provided input and output against the provided file path. - **file_input**: A string that represents the contents of a file before changes. - **file_output**: A string that represents the contents of a file after changes. - **file_path**: A Path object that represents the file path of the file being changed. - **output**: A stream to output the diff to. If non is provided uses sys.stdout. - **color_output**: Use color in output if True. """ printer = create_terminal_printer(color_output, output) file_name = "" if file_path is None else str(file_path) file_mtime = str( datetime.now() if file_path is None else datetime.fromtimestamp(file_path.stat().st_mtime) ) unified_diff_lines = unified_diff( file_input.splitlines(keepends=True), file_output.splitlines(keepends=True), fromfile=file_name + ":before", tofile=file_name + ":after", fromfiledate=file_mtime, tofiledate=str(datetime.now()), ) for line in unified_diff_lines: printer.diff_line(line) def ask_whether_to_apply_changes_to_file(file_path: str) -> bool: answer = None while answer not in ("yes", "y", "no", "n", "quit", "q"): answer = input(f"Apply suggested changes to '{file_path}' [y/n/q]? ") # nosec answer = answer.lower() if answer in ("no", "n"): return False if answer in ("quit", "q"): sys.exit(1) return True def remove_whitespace(content: str, line_separator: str = "\n") -> str: content = content.replace(line_separator, "").replace(" ", "").replace("\x0c", "") return content class BasicPrinter: ERROR = "ERROR" SUCCESS = "SUCCESS" def __init__(self, error: str, success: str, output: Optional[TextIO] = None): self.output = output or sys.stdout self.success_message = success self.error_message = error def success(self, message: str) -> None: print(self.success_message.format(success=self.SUCCESS, message=message), file=self.output) def error(self, message: str) -> None: print(self.error_message.format(error=self.ERROR, message=message), file=sys.stderr) def diff_line(self, line: str) -> None: self.output.write(line) class ColoramaPrinter(BasicPrinter): def __init__(self, error: str, success: str, output: Optional[TextIO]): super().__init__(error, success, output=output) # Note: this constants are instance variables instead ofs class variables # because they refer to colorama which might not be installed. self.ERROR = self.style_text("ERROR", colorama.Fore.RED) self.SUCCESS = self.style_text("SUCCESS", colorama.Fore.GREEN) self.ADDED_LINE = colorama.Fore.GREEN self.REMOVED_LINE = colorama.Fore.RED @staticmethod def style_text(text: str, style: Optional[str] = None) -> str: if style is None: return text return style + text + str(colorama.Style.RESET_ALL) def diff_line(self, line: str) -> None: style = None if re.match(ADDED_LINE_PATTERN, line): style = self.ADDED_LINE elif re.match(REMOVED_LINE_PATTERN, line): style = self.REMOVED_LINE self.output.write(self.style_text(line, style)) def create_terminal_printer( color: bool, output: Optional[TextIO] = None, error: str = "", success: str = "" ) -> BasicPrinter: if color and colorama_unavailable: no_colorama_message = ( "\n" "Sorry, but to use --color (color_output) the colorama python package is required.\n\n" "Reference: https://pypi.org/project/colorama/\n\n" "You can either install it separately on your system or as the colors extra " "for isort. Ex: \n\n" "$ pip install isort[colors]\n" ) print(no_colorama_message, file=sys.stderr) sys.exit(1) if not colorama_unavailable: colorama.init(strip=False) return ( ColoramaPrinter(error, success, output) if color else BasicPrinter(error, success, output) ) isort-6.0.1/isort/hooks.py0000644000000000000000000000641313615410400012437 0ustar00"""Defines a git hook to allow pre-commit warnings and errors about import order. usage: exit_code = git_hook(strict=True|False, modify=True|False) """ import os import subprocess # nosec - Needed for hook from pathlib import Path from typing import List, Optional from isort import Config, api, exceptions def get_output(command: List[str]) -> str: """Run a command and return raw output :param str command: the command to run :returns: the stdout output of the command """ result = subprocess.run(command, stdout=subprocess.PIPE, check=True) # nosec - trusted input return result.stdout.decode() def get_lines(command: List[str]) -> List[str]: """Run a command and return lines of output :param str command: the command to run :returns: list of whitespace-stripped lines output by command """ stdout = get_output(command) return [line.strip() for line in stdout.splitlines()] def git_hook( strict: bool = False, modify: bool = False, lazy: bool = False, settings_file: str = "", directories: Optional[List[str]] = None, ) -> int: """Git pre-commit hook to check staged files for isort errors :param bool strict - if True, return number of errors on exit, causing the hook to fail. If False, return zero so it will just act as a warning. :param bool modify - if True, fix the sources if they are not sorted properly. If False, only report result without modifying anything. :param bool lazy - if True, also check/fix unstaged files. This is useful if you frequently use ``git commit -a`` for example. If False, only check/fix the staged files for isort errors. :param str settings_file - A path to a file to be used as the configuration file for this run. When settings_file is the empty string, the configuration file will be searched starting at the directory containing the first staged file, if any, and going upward in the directory structure. :param list[str] directories - A list of directories to restrict the hook to. :return number of errors if in strict mode, 0 otherwise. """ # Get list of files modified and staged diff_cmd = ["git", "diff-index", "--cached", "--name-only", "--diff-filter=ACMRTUXB", "HEAD"] if lazy: diff_cmd.remove("--cached") if directories: diff_cmd.extend(directories) files_modified = get_lines(diff_cmd) if not files_modified: return 0 errors = 0 config = Config( settings_file=settings_file, settings_path=os.path.dirname(os.path.abspath(files_modified[0])), ) for filename in files_modified: if filename.endswith(".py"): # Get the staged contents of the file staged_cmd = ["git", "show", f":{filename}"] staged_contents = get_output(staged_cmd) try: if not api.check_code_string( staged_contents, file_path=Path(filename), config=config ): errors += 1 if modify: api.sort_file(filename, config=config) except exceptions.FileSkipped: # pragma: no cover pass return errors if strict else 0 isort-6.0.1/isort/identify.py0000644000000000000000000002023013615410400013120 0ustar00"""Fast stream based import identification. Eventually this will likely replace parse.py """ from functools import partial from pathlib import Path from typing import Iterator, NamedTuple, Optional, TextIO, Tuple from isort.parse import normalize_line, skip_line, strip_syntax from .comments import parse as parse_comments from .settings import DEFAULT_CONFIG, Config STATEMENT_DECLARATIONS: Tuple[str, ...] = ("def ", "cdef ", "cpdef ", "class ", "@", "async def") class Import(NamedTuple): line_number: int indented: bool module: str attribute: Optional[str] = None alias: Optional[str] = None cimport: bool = False file_path: Optional[Path] = None def statement(self) -> str: import_cmd = "cimport" if self.cimport else "import" if self.attribute: import_string = f"from {self.module} {import_cmd} {self.attribute}" else: import_string = f"{import_cmd} {self.module}" if self.alias: import_string += f" as {self.alias}" return import_string def __str__(self) -> str: return ( f"{self.file_path or ''}:{self.line_number} " f"{'indented ' if self.indented else ''}{self.statement()}" ) def imports( input_stream: TextIO, config: Config = DEFAULT_CONFIG, file_path: Optional[Path] = None, top_only: bool = False, ) -> Iterator[Import]: """Parses a python file taking out and categorizing imports.""" in_quote = "" indexed_input = enumerate(input_stream) for index, raw_line in indexed_input: (skipping_line, in_quote) = skip_line( raw_line, in_quote=in_quote, index=index, section_comments=config.section_comments ) if top_only and not in_quote and raw_line.startswith(STATEMENT_DECLARATIONS): break if skipping_line: continue stripped_line = raw_line.strip().split("#")[0] if stripped_line.startswith(("raise", "yield")): if stripped_line == "yield": while not stripped_line or stripped_line == "yield": try: index, next_line = next(indexed_input) except StopIteration: break stripped_line = next_line.strip().split("#")[0] while stripped_line.endswith("\\"): try: index, next_line = next(indexed_input) except StopIteration: break stripped_line = next_line.strip().split("#")[0] continue # pragma: no cover line, *end_of_line_comment = raw_line.split("#", 1) statements = [line.strip() for line in line.split(";")] if end_of_line_comment: statements[-1] = f"{statements[-1]}#{end_of_line_comment[0]}" for statement in statements: line, _raw_line = normalize_line(statement) if line.startswith(("import ", "cimport ")): type_of_import = "straight" elif line.startswith("from "): type_of_import = "from" else: continue # pragma: no cover import_string, _ = parse_comments(line) normalized_import_string = ( import_string.replace("import(", "import (").replace("\\", " ").replace("\n", " ") ) cimports: bool = ( " cimport " in normalized_import_string or normalized_import_string.startswith("cimport") ) identified_import = partial( Import, index + 1, # line numbers use 1 based indexing raw_line.startswith((" ", "\t")), cimport=cimports, file_path=file_path, ) if "(" in line.split("#", 1)[0]: while not line.split("#")[0].strip().endswith(")"): try: index, next_line = next(indexed_input) except StopIteration: break line, _ = parse_comments(next_line) import_string += "\n" + line else: while line.strip().endswith("\\"): try: index, next_line = next(indexed_input) except StopIteration: break line, _ = parse_comments(next_line) # Still need to check for parentheses after an escaped line if "(" in line.split("#")[0] and ")" not in line.split("#")[0]: import_string += "\n" + line while not line.split("#")[0].strip().endswith(")"): try: index, next_line = next(indexed_input) except StopIteration: break line, _ = parse_comments(next_line) import_string += "\n" + line else: if import_string.strip().endswith( (" import", " cimport") ) or line.strip().startswith(("import ", "cimport ")): import_string += "\n" + line else: import_string = ( import_string.rstrip().rstrip("\\") + " " + line.lstrip() ) if type_of_import == "from": import_string = ( import_string.replace("import(", "import (") .replace("\\", " ") .replace("\n", " ") ) parts = import_string.split(" cimport " if cimports else " import ") from_import = parts[0].split(" ") import_string = (" cimport " if cimports else " import ").join( [from_import[0] + " " + "".join(from_import[1:])] + parts[1:] ) just_imports = [ item.replace("{|", "{ ").replace("|}", " }") for item in strip_syntax(import_string).split() ] direct_imports = just_imports[1:] top_level_module = "" if "as" in just_imports and (just_imports.index("as") + 1) < len(just_imports): while "as" in just_imports: attribute = None as_index = just_imports.index("as") if type_of_import == "from": attribute = just_imports[as_index - 1] top_level_module = just_imports[0] module = top_level_module + "." + attribute alias = just_imports[as_index + 1] direct_imports.remove(attribute) direct_imports.remove(alias) direct_imports.remove("as") just_imports[1:] = direct_imports if attribute == alias and config.remove_redundant_aliases: yield identified_import(top_level_module, attribute) else: yield identified_import(top_level_module, attribute, alias=alias) else: module = just_imports[as_index - 1] alias = just_imports[as_index + 1] just_imports.remove(alias) just_imports.remove("as") just_imports.remove(module) if module == alias and config.remove_redundant_aliases: yield identified_import(module) else: yield identified_import(module, alias=alias) if just_imports: if type_of_import == "from": module = just_imports.pop(0) for attribute in just_imports: yield identified_import(module, attribute) else: for module in just_imports: yield identified_import(module) isort-6.0.1/isort/io.py0000644000000000000000000000425113615410400011721 0ustar00"""Defines any IO utilities used by isort""" import dataclasses import re import tokenize from contextlib import contextmanager from io import BytesIO, StringIO, TextIOWrapper from pathlib import Path from typing import Any, Callable, Iterator, TextIO, Union from isort.exceptions import UnsupportedEncoding _ENCODING_PATTERN = re.compile(rb"^[ \t\f]*#.*?coding[:=][ \t]*([-_.a-zA-Z0-9]+)") @dataclasses.dataclass(frozen=True) class File: stream: TextIO path: Path encoding: str @staticmethod def detect_encoding(filename: Union[str, Path], readline: Callable[[], bytes]) -> str: try: return tokenize.detect_encoding(readline)[0] except Exception: raise UnsupportedEncoding(filename) @staticmethod def from_contents(contents: str, filename: str) -> "File": encoding = File.detect_encoding(filename, BytesIO(contents.encode("utf-8")).readline) return File(stream=StringIO(contents), path=Path(filename).resolve(), encoding=encoding) @property def extension(self) -> str: return self.path.suffix.lstrip(".") @staticmethod def _open(filename: Union[str, Path]) -> TextIOWrapper: """Open a file in read only mode using the encoding detected by detect_encoding(). """ buffer = open(filename, "rb") try: encoding = File.detect_encoding(filename, buffer.readline) buffer.seek(0) text = TextIOWrapper(buffer, encoding, line_buffering=True, newline="") text.mode = "r" # type: ignore return text except Exception: buffer.close() raise @staticmethod @contextmanager def read(filename: Union[str, Path]) -> Iterator["File"]: file_path = Path(filename).resolve() stream = None try: stream = File._open(file_path) yield File(stream=stream, path=file_path, encoding=stream.encoding) finally: if stream is not None: stream.close() class _EmptyIO(StringIO): def write(self, *args: Any, **kwargs: Any) -> None: # type: ignore # skipcq: PTC-W0049 pass Empty = _EmptyIO() isort-6.0.1/isort/literal.py0000644000000000000000000000715713615410400012756 0ustar00import ast from pprint import PrettyPrinter from typing import Any, Callable, Dict, List, Set, Tuple from isort.exceptions import ( AssignmentsFormatMismatch, LiteralParsingFailure, LiteralSortTypeMismatch, ) from isort.settings import DEFAULT_CONFIG, Config class ISortPrettyPrinter(PrettyPrinter): """an isort customized pretty printer for sorted literals""" def __init__(self, config: Config): super().__init__(width=config.line_length, compact=True) type_mapping: Dict[str, Tuple[type, Callable[[Any, ISortPrettyPrinter], str]]] = {} def assignments(code: str) -> str: values = {} for line in code.splitlines(keepends=True): if not line.strip(): continue if " = " not in line: raise AssignmentsFormatMismatch(code) variable_name, value = line.split(" = ", 1) values[variable_name] = value return "".join( f"{variable_name} = {values[variable_name]}" for variable_name in sorted(values.keys()) ) def assignment(code: str, sort_type: str, extension: str, config: Config = DEFAULT_CONFIG) -> str: """Sorts the literal present within the provided code against the provided sort type, returning the sorted representation of the source code. """ if sort_type == "assignments": return assignments(code) if sort_type not in type_mapping: raise ValueError( "Trying to sort using an undefined sort_type. " f"Defined sort types are {', '.join(type_mapping.keys())}." ) variable_name, literal = code.split("=") variable_name = variable_name.strip() literal = literal.lstrip() try: value = ast.literal_eval(literal) except Exception as error: raise LiteralParsingFailure(code, error) expected_type, sort_function = type_mapping[sort_type] if type(value) is not expected_type: raise LiteralSortTypeMismatch(type(value), expected_type) printer = ISortPrettyPrinter(config) sorted_value_code = f"{variable_name} = {sort_function(value, printer)}" if config.formatting_function: sorted_value_code = config.formatting_function( sorted_value_code, extension, config ).rstrip() sorted_value_code += code[len(code.rstrip()) :] return sorted_value_code def register_type( name: str, kind: type ) -> Callable[[Callable[[Any, ISortPrettyPrinter], str]], Callable[[Any, ISortPrettyPrinter], str]]: """Registers a new literal sort type.""" def wrap( function: Callable[[Any, ISortPrettyPrinter], str] ) -> Callable[[Any, ISortPrettyPrinter], str]: type_mapping[name] = (kind, function) return function return wrap @register_type("dict", dict) def _dict(value: Dict[Any, Any], printer: ISortPrettyPrinter) -> str: return printer.pformat(dict(sorted(value.items(), key=lambda item: item[1]))) @register_type("list", list) def _list(value: List[Any], printer: ISortPrettyPrinter) -> str: return printer.pformat(sorted(value)) @register_type("unique-list", list) def _unique_list(value: List[Any], printer: ISortPrettyPrinter) -> str: return printer.pformat(sorted(set(value))) @register_type("set", set) def _set(value: Set[Any], printer: ISortPrettyPrinter) -> str: return "{" + printer.pformat(tuple(sorted(value)))[1:-1] + "}" @register_type("tuple", tuple) def _tuple(value: Tuple[Any, ...], printer: ISortPrettyPrinter) -> str: return printer.pformat(tuple(sorted(value))) @register_type("unique-tuple", tuple) def _unique_tuple(value: Tuple[Any, ...], printer: ISortPrettyPrinter) -> str: return printer.pformat(tuple(sorted(set(value)))) isort-6.0.1/isort/logo.py0000644000000000000000000000060413615410400012250 0ustar00from ._version import __version__ ASCII_ART = rf""" _ _ (_) ___ ___ _ __| |_ | |/ _/ / _ \/ '__ _/ | |\__ \/\_\/| | | |_ |_|\___/\___/\_/ \_/ isort your imports, so you don't have to. VERSION {__version__} """ __doc__ = f""" ```python {ASCII_ART} ``` """ isort-6.0.1/isort/main.py0000644000000000000000000013403613615410400012243 0ustar00"""Tool for sorting imports alphabetically, and automatically separated into sections.""" import argparse import functools import json import os import sys from gettext import gettext as _ from io import TextIOWrapper from pathlib import Path from typing import Any, Dict, List, Optional, Sequence, Union from warnings import warn from . import __version__, api, files, sections from .exceptions import FileSkipped, ISortError, UnsupportedEncoding from .format import create_terminal_printer from .logo import ASCII_ART from .profiles import profiles from .settings import VALID_PY_TARGETS, Config, find_all_configs from .utils import Trie from .wrap_modes import WrapModes DEPRECATED_SINGLE_DASH_ARGS = { "-ac", "-af", "-ca", "-cs", "-df", "-ds", "-dt", "-fas", "-fass", "-ff", "-fgw", "-fss", "-lai", "-lbt", "-le", "-ls", "-nis", "-nlb", "-ot", "-rr", "-sd", "-sg", "-sl", "-sp", "-tc", "-wl", "-ws", } QUICK_GUIDE = f""" {ASCII_ART} Nothing to do: no files or paths have been passed in! Try one of the following: `isort .` - sort all Python files, starting from the current directory, recursively. `isort . --interactive` - Do the same, but ask before making any changes. `isort . --check --diff` - Check to see if imports are correctly sorted within this project. `isort --help` - In-depth information about isort's available command-line options. Visit https://pycqa.github.io/isort/ for complete information about how to use isort. """ class SortAttempt: def __init__(self, incorrectly_sorted: bool, skipped: bool, supported_encoding: bool) -> None: self.incorrectly_sorted = incorrectly_sorted self.skipped = skipped self.supported_encoding = supported_encoding def sort_imports( file_name: str, config: Config, check: bool = False, ask_to_apply: bool = False, write_to_stdout: bool = False, **kwargs: Any, ) -> Optional[SortAttempt]: incorrectly_sorted: bool = False skipped: bool = False try: if check: try: incorrectly_sorted = not api.check_file(file_name, config=config, **kwargs) except FileSkipped: skipped = True return SortAttempt(incorrectly_sorted, skipped, True) try: incorrectly_sorted = not api.sort_file( file_name, config=config, ask_to_apply=ask_to_apply, write_to_stdout=write_to_stdout, **kwargs, ) except FileSkipped: skipped = True return SortAttempt(incorrectly_sorted, skipped, True) except (OSError, ValueError) as error: warn(f"Unable to parse file {file_name} due to {error}", stacklevel=2) return None except UnsupportedEncoding: if config.verbose: warn(f"Encoding not supported for {file_name}", stacklevel=2) return SortAttempt(incorrectly_sorted, skipped, False) except ISortError as error: _print_hard_fail(config, message=str(error)) sys.exit(1) except Exception: _print_hard_fail(config, offending_file=file_name) raise def _print_hard_fail( config: Config, offending_file: Optional[str] = None, message: Optional[str] = None ) -> None: """Fail on unrecoverable exception with custom message.""" message = message or ( f"Unrecoverable exception thrown when parsing {offending_file or ''}! " "This should NEVER happen.\n" "If encountered, please open an issue: https://github.com/PyCQA/isort/issues/new" ) printer = create_terminal_printer( color=config.color_output, error=config.format_error, success=config.format_success ) printer.error(message) def _build_arg_parser() -> argparse.ArgumentParser: parser = argparse.ArgumentParser( description="Sort Python import definitions alphabetically " "within logical sections. Run with no arguments to see a quick " "start guide, otherwise, one or more files/directories/stdin must be provided. " "Use `-` as the first argument to represent stdin. Use --interactive to use the pre 5.0.0 " "interactive behavior." " " "If you've used isort 4 but are new to isort 5, see the upgrading guide: " "https://pycqa.github.io/isort/docs/upgrade_guides/5.0.0.html", add_help=False, # prevent help option from appearing in "optional arguments" group ) general_group = parser.add_argument_group("general options") target_group = parser.add_argument_group("target options") output_group = parser.add_argument_group("general output options") inline_args_group = output_group.add_mutually_exclusive_group() section_group = parser.add_argument_group("section output options") deprecated_group = parser.add_argument_group("deprecated options") general_group.add_argument( "-h", "--help", action="help", default=argparse.SUPPRESS, help=_("show this help message and exit"), ) general_group.add_argument( "-V", "--version", action="store_true", dest="show_version", help="Displays the currently installed version of isort.", ) general_group.add_argument( "--vn", "--version-number", action="version", version=__version__, help="Returns just the current version number without the logo", ) general_group.add_argument( "-v", "--verbose", action="store_true", dest="verbose", help="Shows verbose output, such as when files are skipped or when a check is successful.", ) general_group.add_argument( "--only-modified", "--om", dest="only_modified", action="store_true", help="Suppresses verbose output for non-modified files.", ) general_group.add_argument( "--dedup-headings", dest="dedup_headings", action="store_true", help="Tells isort to only show an identical custom import heading comment once, even if" " there are multiple sections with the comment set.", ) general_group.add_argument( "-q", "--quiet", action="store_true", dest="quiet", help="Shows extra quiet output, only errors are outputted.", ) general_group.add_argument( "-d", "--stdout", help="Force resulting output to stdout, instead of in-place.", dest="write_to_stdout", action="store_true", ) general_group.add_argument( "--overwrite-in-place", help="Tells isort to overwrite in place using the same file handle. " "Comes at a performance and memory usage penalty over its standard " "approach but ensures all file flags and modes stay unchanged.", dest="overwrite_in_place", action="store_true", ) general_group.add_argument( "--show-config", dest="show_config", action="store_true", help="See isort's determined config, as well as sources of config options.", ) general_group.add_argument( "--show-files", dest="show_files", action="store_true", help="See the files isort will be run against with the current config options.", ) general_group.add_argument( "--df", "--diff", dest="show_diff", action="store_true", help="Prints a diff of all the changes isort would make to a file, instead of " "changing it in place", ) general_group.add_argument( "-c", "--check-only", "--check", action="store_true", dest="check", help="Checks the file for unsorted / unformatted imports and prints them to the " "command line without modifying the file. Returns 0 when nothing would change and " "returns 1 when the file would be reformatted.", ) general_group.add_argument( "--ws", "--ignore-whitespace", action="store_true", dest="ignore_whitespace", help="Tells isort to ignore whitespace differences when --check-only is being used.", ) general_group.add_argument( "--sp", "--settings-path", "--settings-file", "--settings", dest="settings_path", help="Explicitly set the settings path or file instead of auto determining " "based on file location.", ) general_group.add_argument( "--cr", "--config-root", dest="config_root", help="Explicitly set the config root for resolving all configs. When used " "with the --resolve-all-configs flag, isort will look at all sub-folders " "in this config root to resolve config files and sort files based on the " "closest available config(if any)", ) general_group.add_argument( "--resolve-all-configs", dest="resolve_all_configs", action="store_true", help="Tells isort to resolve the configs for all sub-directories " "and sort files in terms of its closest config files.", ) general_group.add_argument( "--profile", dest="profile", type=str, help="Base profile type to use for configuration. " f"Profiles include: {', '.join(profiles.keys())}. As well as any shared profiles.", ) general_group.add_argument( "--old-finders", "--magic-placement", dest="old_finders", action="store_true", help="Use the old deprecated finder logic that relies on environment introspection magic.", ) general_group.add_argument( "-j", "--jobs", help="Number of files to process in parallel. Negative value means use number of CPUs.", dest="jobs", type=int, nargs="?", const=-1, ) general_group.add_argument( "--ac", "--atomic", dest="atomic", action="store_true", help="Ensures the output doesn't save if the resulting file contains syntax errors.", ) general_group.add_argument( "--interactive", dest="ask_to_apply", action="store_true", help="Tells isort to apply changes interactively.", ) general_group.add_argument( "--format-error", dest="format_error", help="Override the format used to print errors.", ) general_group.add_argument( "--format-success", dest="format_success", help="Override the format used to print success.", ) general_group.add_argument( "--srx", "--sort-reexports", dest="sort_reexports", action="store_true", help="Automatically sort all re-exports (module level __all__ collections)", ) target_group.add_argument( "files", nargs="*", help="One or more Python source files that need their imports sorted." ) target_group.add_argument( "--filter-files", dest="filter_files", action="store_true", help="Tells isort to filter files even when they are explicitly passed in as " "part of the CLI command.", ) target_group.add_argument( "-s", "--skip", help="Files that isort should skip over. If you want to skip multiple " "files you should specify twice: --skip file1 --skip file2. Values can be " "file names, directory names or file paths. To skip all files in a nested path " "use --skip-glob.", dest="skip", action="append", ) target_group.add_argument( "--extend-skip", help="Extends --skip to add additional files that isort should skip over. " "If you want to skip multiple " "files you should specify twice: --skip file1 --skip file2. Values can be " "file names, directory names or file paths. To skip all files in a nested path " "use --skip-glob.", dest="extend_skip", action="append", ) target_group.add_argument( "--sg", "--skip-glob", help="Files that isort should skip over.", dest="skip_glob", action="append", ) target_group.add_argument( "--extend-skip-glob", help="Additional files that isort should skip over (extending --skip-glob).", dest="extend_skip_glob", action="append", ) target_group.add_argument( "--gitignore", "--skip-gitignore", action="store_true", dest="skip_gitignore", help="Treat project as a git repository and ignore files listed in .gitignore." "\nNOTE: This requires git to be installed and accessible from the same shell as isort.", ) target_group.add_argument( "--ext", "--extension", "--supported-extension", dest="supported_extensions", action="append", help="Specifies what extensions isort can be run against.", ) target_group.add_argument( "--blocked-extension", dest="blocked_extensions", action="append", help="Specifies what extensions isort can never be run against.", ) target_group.add_argument( "--dont-follow-links", dest="dont_follow_links", action="store_true", help="Tells isort not to follow symlinks that are encountered when running recursively.", ) target_group.add_argument( "--filename", dest="filename", help="Provide the filename associated with a stream.", ) target_group.add_argument( "--allow-root", action="store_true", default=False, help="Tells isort not to treat / specially, allowing it to be run against the root dir.", ) output_group.add_argument( "-a", "--add-import", dest="add_imports", action="append", help="Adds the specified import line to all files, " "automatically determining correct placement.", ) output_group.add_argument( "--append", "--append-only", dest="append_only", action="store_true", help="Only adds the imports specified in --add-import if the file" " contains existing imports.", ) output_group.add_argument( "--af", "--force-adds", dest="force_adds", action="store_true", help="Forces import adds even if the original file is empty.", ) output_group.add_argument( "--rm", "--remove-import", dest="remove_imports", action="append", help="Removes the specified import from all files.", ) output_group.add_argument( "--float-to-top", dest="float_to_top", action="store_true", help="Causes all non-indented imports to float to the top of the file having its imports " "sorted (immediately below the top of file comment).\n" "This can be an excellent shortcut for collecting imports every once in a while " "when you place them in the middle of a file to avoid context switching.\n\n" "*NOTE*: It currently doesn't work with cimports and introduces some extra over-head " "and a performance penalty.", ) output_group.add_argument( "--dont-float-to-top", dest="dont_float_to_top", action="store_true", help="Forces --float-to-top setting off. See --float-to-top for more information.", ) output_group.add_argument( "--ca", "--combine-as", dest="combine_as_imports", action="store_true", help="Combines as imports on the same line.", ) output_group.add_argument( "--cs", "--combine-star", dest="combine_star", action="store_true", help="Ensures that if a star import is present, " "nothing else is imported from that namespace.", ) output_group.add_argument( "-e", "--balanced", dest="balanced_wrapping", action="store_true", help="Balances wrapping to produce the most consistent line length possible", ) output_group.add_argument( "--ff", "--from-first", dest="from_first", action="store_true", help="Switches the typical ordering preference, " "showing from imports first then straight ones.", ) output_group.add_argument( "--fgw", "--force-grid-wrap", nargs="?", const=2, type=int, dest="force_grid_wrap", help="Force number of from imports (defaults to 2 when passed as CLI flag without value) " "to be grid wrapped regardless of line " "length. If 0 is passed in (the global default) only line length is considered.", ) output_group.add_argument( "-i", "--indent", help='String to place for indents defaults to " " (4 spaces).', dest="indent", type=str, ) output_group.add_argument( "--lbi", "--lines-before-imports", dest="lines_before_imports", type=int ) output_group.add_argument( "--lai", "--lines-after-imports", dest="lines_after_imports", type=int ) output_group.add_argument( "--lbt", "--lines-between-types", dest="lines_between_types", type=int ) output_group.add_argument( "--le", "--line-ending", dest="line_ending", help="Forces line endings to the specified value. " "If not set, values will be guessed per-file.", ) output_group.add_argument( "--ls", "--length-sort", help="Sort imports by their string length.", dest="length_sort", action="store_true", ) output_group.add_argument( "--lss", "--length-sort-straight", help="Sort straight imports by their string length. Similar to `length_sort` " "but applies only to straight imports and doesn't affect from imports.", dest="length_sort_straight", action="store_true", ) output_group.add_argument( "-m", "--multi-line", dest="multi_line_output", choices=list(WrapModes.__members__.keys()) + [str(mode.value) for mode in WrapModes.__members__.values()], type=str, help="Multi line output (0-grid, 1-vertical, 2-hanging, 3-vert-hanging, 4-vert-grid, " "5-vert-grid-grouped, 6-deprecated-alias-for-5, 7-noqa, " "8-vertical-hanging-indent-bracket, 9-vertical-prefix-from-module-import, " "10-hanging-indent-with-parentheses).", ) output_group.add_argument( "-n", "--ensure-newline-before-comments", dest="ensure_newline_before_comments", action="store_true", help="Inserts a blank line before a comment following an import.", ) inline_args_group.add_argument( "--nis", "--no-inline-sort", dest="no_inline_sort", action="store_true", help="Leaves `from` imports with multiple imports 'as-is' " "(e.g. `from foo import a, c ,b`).", ) output_group.add_argument( "--ot", "--order-by-type", dest="order_by_type", action="store_true", help="Order imports by type, which is determined by case, in addition to alphabetically.\n" "\n**NOTE**: type here refers to the implied type from the import name capitalization.\n" ' isort does not do type introspection for the imports. These "types" are simply: ' "CONSTANT_VARIABLE, CamelCaseClass, variable_or_function. If your project follows PEP8" " or a related coding standard and has many imports this is a good default, otherwise you " "likely will want to turn it off. From the CLI the `--dont-order-by-type` option will turn " "this off.", ) output_group.add_argument( "--dt", "--dont-order-by-type", dest="dont_order_by_type", action="store_true", help="Don't order imports by type, which is determined by case, in addition to " "alphabetically.\n\n" "**NOTE**: type here refers to the implied type from the import name capitalization.\n" ' isort does not do type introspection for the imports. These "types" are simply: ' "CONSTANT_VARIABLE, CamelCaseClass, variable_or_function. If your project follows PEP8" " or a related coding standard and has many imports this is a good default. You can turn " "this on from the CLI using `--order-by-type`.", ) output_group.add_argument( "--rr", "--reverse-relative", dest="reverse_relative", action="store_true", help="Reverse order of relative imports.", ) output_group.add_argument( "--reverse-sort", dest="reverse_sort", action="store_true", help="Reverses the ordering of imports.", ) output_group.add_argument( "--sort-order", dest="sort_order", help="Specify sorting function. Can be built in (natural[default] = force numbers " "to be sequential, native = Python's built-in sorted function) or an installable plugin.", ) inline_args_group.add_argument( "--sl", "--force-single-line-imports", dest="force_single_line", action="store_true", help="Forces all from imports to appear on their own line", ) output_group.add_argument( "--nsl", "--single-line-exclusions", help="One or more modules to exclude from the single line rule.", dest="single_line_exclusions", action="append", ) output_group.add_argument( "--tc", "--trailing-comma", dest="include_trailing_comma", action="store_true", help="Includes a trailing comma on multi line imports that include parentheses.", ) output_group.add_argument( "--up", "--use-parentheses", dest="use_parentheses", action="store_true", help="Use parentheses for line continuation on length limit instead of slashes." " **NOTE**: This is separate from wrap modes, and only affects how individual lines that " " are too long get continued, not sections of multiple imports.", ) output_group.add_argument( "-l", "-w", "--line-length", "--line-width", help="The max length of an import line (used for wrapping long imports).", dest="line_length", type=int, ) output_group.add_argument( "--wl", "--wrap-length", dest="wrap_length", type=int, help="Specifies how long lines that are wrapped should be, if not set line_length is used." "\nNOTE: wrap_length must be LOWER than or equal to line_length.", ) output_group.add_argument( "--case-sensitive", dest="case_sensitive", action="store_true", help="Tells isort to include casing when sorting module names", ) output_group.add_argument( "--remove-redundant-aliases", dest="remove_redundant_aliases", action="store_true", help=( "Tells isort to remove redundant aliases from imports, such as `import os as os`." " This defaults to `False` simply because some projects use these seemingly useless " " aliases to signify intent and change behaviour." ), ) output_group.add_argument( "--honor-noqa", dest="honor_noqa", action="store_true", help="Tells isort to honor noqa comments to enforce skipping those comments.", ) output_group.add_argument( "--treat-comment-as-code", dest="treat_comments_as_code", action="append", help="Tells isort to treat the specified single line comment(s) as if they are code.", ) output_group.add_argument( "--treat-all-comment-as-code", dest="treat_all_comments_as_code", action="store_true", help="Tells isort to treat all single line comments as if they are code.", ) output_group.add_argument( "--formatter", dest="formatter", type=str, help="Specifies the name of a formatting plugin to use when producing output.", ) output_group.add_argument( "--color", dest="color_output", action="store_true", help="Tells isort to use color in terminal output.", ) output_group.add_argument( "--ext-format", dest="ext_format", help="Tells isort to format the given files according to an extensions formatting rules.", ) output_group.add_argument( "--star-first", help="Forces star imports above others to avoid overriding directly imported variables.", dest="star_first", action="store_true", ) output_group.add_argument( "--split-on-trailing-comma", help="Split imports list followed by a trailing comma into VERTICAL_HANGING_INDENT mode", dest="split_on_trailing_comma", action="store_true", ) section_group.add_argument( "--sd", "--section-default", dest="default_section", help="Sets the default section for import options: " + str(sections.DEFAULT), ) section_group.add_argument( "--only-sections", "--os", dest="only_sections", action="store_true", help="Causes imports to be sorted based on their sections like STDLIB, THIRDPARTY, etc. " "Within sections, the imports are ordered by their import style and the imports with " "the same style maintain their relative positions.", ) section_group.add_argument( "--ds", "--no-sections", help="Put all imports into the same section bucket", dest="no_sections", action="store_true", ) section_group.add_argument( "--fas", "--force-alphabetical-sort", action="store_true", dest="force_alphabetical_sort", help="Force all imports to be sorted as a single section", ) section_group.add_argument( "--fss", "--force-sort-within-sections", action="store_true", dest="force_sort_within_sections", help="Don't sort straight-style imports (like import sys) before from-style imports " "(like from itertools import groupby). Instead, sort the imports by module, " "independent of import style.", ) section_group.add_argument( "--hcss", "--honor-case-in-force-sorted-sections", action="store_true", dest="honor_case_in_force_sorted_sections", help="Honor `--case-sensitive` when `--force-sort-within-sections` is being used. " "Without this option set, `--order-by-type` decides module name ordering too.", ) section_group.add_argument( "--srss", "--sort-relative-in-force-sorted-sections", action="store_true", dest="sort_relative_in_force_sorted_sections", help="When using `--force-sort-within-sections`, sort relative imports the same " "way as they are sorted when not using that setting.", ) section_group.add_argument( "--fass", "--force-alphabetical-sort-within-sections", action="store_true", dest="force_alphabetical_sort_within_sections", help="Force all imports to be sorted alphabetically within a section", ) section_group.add_argument( "-t", "--top", help="Force specific imports to the top of their appropriate section.", dest="force_to_top", action="append", ) section_group.add_argument( "--combine-straight-imports", "--csi", dest="combine_straight_imports", action="store_true", help="Combines all the bare straight imports of the same section in a single line. " "Won't work with sections which have 'as' imports", ) section_group.add_argument( "--nlb", "--no-lines-before", help="Sections which should not be split with previous by empty lines", dest="no_lines_before", action="append", ) section_group.add_argument( "--src", "--src-path", dest="src_paths", action="append", help="Add an explicitly defined source path " "(modules within src paths have their imports automatically categorized as first_party)." " Glob expansion (`*` and `**`) is supported for this option.", ) section_group.add_argument( "-b", "--builtin", dest="known_standard_library", action="append", help="Force isort to recognize a module as part of Python's standard library.", ) section_group.add_argument( "--extra-builtin", dest="extra_standard_library", action="append", help="Extra modules to be included in the list of ones in Python's standard library.", ) section_group.add_argument( "-f", "--future", dest="known_future_library", action="append", help="Force isort to recognize a module as part of Python's internal future compatibility " "libraries. WARNING: this overrides the behavior of __future__ handling and therefore" " can result in code that can't execute. If you're looking to add dependencies such " "as six, a better option is to create another section below --future using custom " "sections. See: https://github.com/PyCQA/isort#custom-sections-and-ordering and the " "discussion here: https://github.com/PyCQA/isort/issues/1463.", ) section_group.add_argument( "-o", "--thirdparty", dest="known_third_party", action="append", help="Force isort to recognize a module as being part of a third party library.", ) section_group.add_argument( "-p", "--project", dest="known_first_party", action="append", help="Force isort to recognize a module as being part of the current python project.", ) section_group.add_argument( "--known-local-folder", dest="known_local_folder", action="append", help="Force isort to recognize a module as being a local folder. " "Generally, this is reserved for relative imports (from . import module).", ) section_group.add_argument( "--virtual-env", dest="virtual_env", help="Virtual environment to use for determining whether a package is third-party", ) section_group.add_argument( "--conda-env", dest="conda_env", help="Conda environment to use for determining whether a package is third-party", ) section_group.add_argument( "--py", "--python-version", action="store", dest="py_version", choices=(*tuple(VALID_PY_TARGETS), "auto"), help="Tells isort to set the known standard library based on the specified Python " "version. Default is to assume any Python 3 version could be the target, and use a union " "of all stdlib modules across versions. If auto is specified, the version of the " "interpreter used to run isort " f"(currently: {sys.version_info.major}{sys.version_info.minor}) will be used.", ) # deprecated options deprecated_group.add_argument( "--recursive", dest="deprecated_flags", action="append_const", const="--recursive", help=argparse.SUPPRESS, ) deprecated_group.add_argument( "-rc", dest="deprecated_flags", action="append_const", const="-rc", help=argparse.SUPPRESS ) deprecated_group.add_argument( "--dont-skip", dest="deprecated_flags", action="append_const", const="--dont-skip", help=argparse.SUPPRESS, ) deprecated_group.add_argument( "-ns", dest="deprecated_flags", action="append_const", const="-ns", help=argparse.SUPPRESS ) deprecated_group.add_argument( "--apply", dest="deprecated_flags", action="append_const", const="--apply", help=argparse.SUPPRESS, ) deprecated_group.add_argument( "-k", "--keep-direct-and-as", dest="deprecated_flags", action="append_const", const="--keep-direct-and-as", help=argparse.SUPPRESS, ) return parser def parse_args(argv: Optional[Sequence[str]] = None) -> Dict[str, Any]: argv = sys.argv[1:] if argv is None else list(argv) remapped_deprecated_args = [] for index, arg in enumerate(argv): if arg in DEPRECATED_SINGLE_DASH_ARGS: remapped_deprecated_args.append(arg) argv[index] = f"-{arg}" parser = _build_arg_parser() arguments = {key: value for key, value in vars(parser.parse_args(argv)).items() if value} if remapped_deprecated_args: arguments["remapped_deprecated_args"] = remapped_deprecated_args if "dont_order_by_type" in arguments: arguments["order_by_type"] = False del arguments["dont_order_by_type"] if "dont_follow_links" in arguments: arguments["follow_links"] = False del arguments["dont_follow_links"] if "dont_float_to_top" in arguments: del arguments["dont_float_to_top"] if arguments.get("float_to_top", False): sys.exit("Can't set both --float-to-top and --dont-float-to-top.") else: arguments["float_to_top"] = False multi_line_output = arguments.get("multi_line_output", None) if multi_line_output: if multi_line_output.isdigit(): arguments["multi_line_output"] = WrapModes(int(multi_line_output)) else: arguments["multi_line_output"] = WrapModes[multi_line_output] return arguments def _preconvert(item: Any) -> Union[str, List[Any]]: """Preconverts objects from native types into JSONifyiable types""" if isinstance(item, (set, frozenset)): return list(item) if isinstance(item, WrapModes): return str(item.name) if isinstance(item, Path): return str(item) if callable(item) and hasattr(item, "__name__"): return str(item.__name__) raise TypeError(f"Unserializable object {item} of type {type(item)}") def identify_imports_main( argv: Optional[Sequence[str]] = None, stdin: Optional[TextIOWrapper] = None ) -> None: parser = argparse.ArgumentParser( description="Get all import definitions from a given file." "Use `-` as the first argument to represent stdin." ) parser.add_argument( "files", nargs="+", help="One or more Python source files that need their imports sorted." ) parser.add_argument( "--top-only", action="store_true", default=False, help="Only identify imports that occur in before functions or classes.", ) target_group = parser.add_argument_group("target options") target_group.add_argument( "--follow-links", action="store_true", default=False, help="Tells isort to follow symlinks that are encountered when running recursively.", ) uniqueness = parser.add_mutually_exclusive_group() uniqueness.add_argument( "--unique", action="store_true", default=False, help="If true, isort will only identify unique imports.", ) uniqueness.add_argument( "--packages", dest="unique", action="store_const", const=api.ImportKey.PACKAGE, default=False, help="If true, isort will only identify the unique top level modules imported.", ) uniqueness.add_argument( "--modules", dest="unique", action="store_const", const=api.ImportKey.MODULE, default=False, help="If true, isort will only identify the unique modules imported.", ) uniqueness.add_argument( "--attributes", dest="unique", action="store_const", const=api.ImportKey.ATTRIBUTE, default=False, help="If true, isort will only identify the unique attributes imported.", ) arguments = parser.parse_args(argv) file_names = arguments.files if file_names == ["-"]: identified_imports = api.find_imports_in_stream( sys.stdin if stdin is None else stdin, unique=arguments.unique, top_only=arguments.top_only, follow_links=arguments.follow_links, ) else: identified_imports = api.find_imports_in_paths( file_names, unique=arguments.unique, top_only=arguments.top_only, follow_links=arguments.follow_links, ) for identified_import in identified_imports: if arguments.unique == api.ImportKey.PACKAGE: print(identified_import.module.split(".")[0]) elif arguments.unique == api.ImportKey.MODULE: print(identified_import.module) elif arguments.unique == api.ImportKey.ATTRIBUTE: print(f"{identified_import.module}.{identified_import.attribute}") else: print(str(identified_import)) def main(argv: Optional[Sequence[str]] = None, stdin: Optional[TextIOWrapper] = None) -> None: arguments = parse_args(argv) if arguments.get("show_version"): print(ASCII_ART) return show_config: bool = arguments.pop("show_config", False) show_files: bool = arguments.pop("show_files", False) if show_config and show_files: sys.exit("Error: either specify show-config or show-files not both.") if "settings_path" in arguments: if os.path.isfile(arguments["settings_path"]): arguments["settings_file"] = os.path.abspath(arguments["settings_path"]) arguments["settings_path"] = os.path.dirname(arguments["settings_file"]) else: arguments["settings_path"] = os.path.abspath(arguments["settings_path"]) if "virtual_env" in arguments: venv = arguments["virtual_env"] arguments["virtual_env"] = os.path.abspath(venv) if not os.path.isdir(arguments["virtual_env"]): warn(f"virtual_env dir does not exist: {arguments['virtual_env']}", stacklevel=2) file_names = arguments.pop("files", []) if not file_names and not show_config: print(QUICK_GUIDE) if arguments: sys.exit("Error: arguments passed in without any paths or content.") return if "settings_path" not in arguments: arguments["settings_path"] = ( arguments.get("filename", None) or os.getcwd() if file_names == ["-"] else os.path.abspath(file_names[0] if file_names else ".") ) if not os.path.isdir(arguments["settings_path"]): arguments["settings_path"] = os.path.dirname(arguments["settings_path"]) config_dict = arguments.copy() ask_to_apply = config_dict.pop("ask_to_apply", False) jobs = config_dict.pop("jobs", None) check = config_dict.pop("check", False) show_diff = config_dict.pop("show_diff", False) write_to_stdout = config_dict.pop("write_to_stdout", False) deprecated_flags = config_dict.pop("deprecated_flags", False) remapped_deprecated_args = config_dict.pop("remapped_deprecated_args", False) stream_filename = config_dict.pop("filename", None) ext_format = config_dict.pop("ext_format", None) allow_root = config_dict.pop("allow_root", None) resolve_all_configs = config_dict.pop("resolve_all_configs", False) wrong_sorted_files = False all_attempt_broken = False no_valid_encodings = False config_trie: Optional[Trie] = None if resolve_all_configs: config_trie = find_all_configs(config_dict.pop("config_root", ".")) if "src_paths" in config_dict: config_dict["src_paths"] = { Path(src_path).resolve() for src_path in config_dict.get("src_paths", ()) } config = Config(**config_dict) if show_config: print(json.dumps(config.__dict__, indent=4, separators=(",", ": "), default=_preconvert)) return if file_names == ["-"]: file_path = Path(stream_filename) if stream_filename else None if show_files: sys.exit("Error: can't show files for streaming input.") input_stream = sys.stdin if stdin is None else stdin if check: incorrectly_sorted = not api.check_stream( input_stream=input_stream, config=config, show_diff=show_diff, file_path=file_path, extension=ext_format, ) wrong_sorted_files = incorrectly_sorted else: try: api.sort_stream( input_stream=input_stream, output_stream=sys.stdout, config=config, show_diff=show_diff, file_path=file_path, extension=ext_format, raise_on_skip=False, ) except FileSkipped: sys.stdout.write(input_stream.read()) elif "/" in file_names and not allow_root: printer = create_terminal_printer( color=config.color_output, error=config.format_error, success=config.format_success ) printer.error("it is dangerous to operate recursively on '/'") printer.error("use --allow-root to override this failsafe") sys.exit(1) else: if stream_filename: printer = create_terminal_printer( color=config.color_output, error=config.format_error, success=config.format_success ) printer.error("Filename override is intended only for stream (-) sorting.") sys.exit(1) skipped: List[str] = [] broken: List[str] = [] if config.filter_files: filtered_files = [] for file_name in file_names: if config.is_skipped(Path(file_name)): skipped.append(file_name) else: filtered_files.append(file_name) file_names = filtered_files file_names = files.find(file_names, config, skipped, broken) if show_files: for file_name in file_names: print(file_name) return num_skipped = 0 num_broken = 0 num_invalid_encoding = 0 if config.verbose: print(ASCII_ART) if jobs: import multiprocessing executor = multiprocessing.Pool(jobs if jobs > 0 else multiprocessing.cpu_count()) attempt_iterator = executor.imap( functools.partial( sort_imports, config=config, check=check, ask_to_apply=ask_to_apply, show_diff=show_diff, write_to_stdout=write_to_stdout, extension=ext_format, config_trie=config_trie, ), file_names, ) else: # https://github.com/python/typeshed/pull/2814 attempt_iterator = ( sort_imports( # type: ignore file_name, config=config, check=check, ask_to_apply=ask_to_apply, show_diff=show_diff, write_to_stdout=write_to_stdout, extension=ext_format, config_trie=config_trie, ) for file_name in file_names ) # If any files passed in are missing considered as error, should be removed is_no_attempt = True any_encoding_valid = False for sort_attempt in attempt_iterator: if not sort_attempt: continue # pragma: no cover - shouldn't happen, satisfies type constraint incorrectly_sorted = sort_attempt.incorrectly_sorted if arguments.get("check", False) and incorrectly_sorted: wrong_sorted_files = True if sort_attempt.skipped: num_skipped += ( 1 # pragma: no cover - shouldn't happen, due to skip in iter_source_code ) if not sort_attempt.supported_encoding: num_invalid_encoding += 1 else: any_encoding_valid = True is_no_attempt = False num_skipped += len(skipped) if num_skipped and not config.quiet: if config.verbose: for was_skipped in skipped: print( f"{was_skipped} was skipped as it's listed in 'skip' setting, " "matches a glob in 'skip_glob' setting, or is in a .gitignore file with " "--skip-gitignore enabled." ) print(f"Skipped {num_skipped} files") num_broken += len(broken) if num_broken and not config.quiet: if config.verbose: for was_broken in broken: warn( f"{was_broken} was broken path, make sure it exists correctly", stacklevel=2 ) print(f"Broken {num_broken} paths") if num_broken > 0 and is_no_attempt: all_attempt_broken = True if num_invalid_encoding > 0 and not any_encoding_valid: no_valid_encodings = True if not config.quiet and (remapped_deprecated_args or deprecated_flags): if remapped_deprecated_args: warn( "W0502: The following deprecated single dash CLI flags were used and translated: " f"{', '.join(remapped_deprecated_args)}!", stacklevel=2, ) if deprecated_flags: warn( "W0501: The following deprecated CLI flags were used and ignored: " f"{', '.join(deprecated_flags)}!", stacklevel=2, ) warn( "W0500: Please see the 5.0.0 Upgrade guide: " "https://pycqa.github.io/isort/docs/upgrade_guides/5.0.0.html", stacklevel=2, ) if wrong_sorted_files: sys.exit(1) if all_attempt_broken: sys.exit(1) if no_valid_encodings: printer = create_terminal_printer( color=config.color_output, error=config.format_error, success=config.format_success ) printer.error("No valid encodings.") sys.exit(1) if __name__ == "__main__": main() isort-6.0.1/isort/output.py0000644000000000000000000006657613615410400012674 0ustar00import copy import itertools from functools import partial from typing import Any, Iterable, List, Optional, Set, Tuple, Type from isort.format import format_simplified from . import parse, sorting, wrap from .comments import add_to_line as with_comments from .identify import STATEMENT_DECLARATIONS from .settings import DEFAULT_CONFIG, Config def sorted_imports( parsed: parse.ParsedContent, config: Config = DEFAULT_CONFIG, extension: str = "py", import_type: str = "import", ) -> str: """Adds the imports back to the file. (at the index of the first import) sorted alphabetically and split between groups """ if parsed.import_index == -1: return _output_as_string(parsed.lines_without_imports, parsed.line_separator) formatted_output: List[str] = parsed.lines_without_imports.copy() remove_imports = [format_simplified(removal) for removal in config.remove_imports] sections: Iterable[str] = itertools.chain(parsed.sections, config.forced_separate) if config.no_sections: parsed.imports["no_sections"] = {"straight": {}, "from": {}} base_sections: Tuple[str, ...] = () for section in sections: if section == "FUTURE": base_sections = ("FUTURE",) continue parsed.imports["no_sections"]["straight"].update( parsed.imports[section].get("straight", {}) ) parsed.imports["no_sections"]["from"].update(parsed.imports[section].get("from", {})) sections = (*base_sections, "no_sections") output: List[str] = [] seen_headings: Set[str] = set() pending_lines_before = False for section in sections: straight_modules = parsed.imports[section]["straight"] if not config.only_sections: straight_modules = sorting.sort( config, straight_modules, key=lambda key: sorting.module_key( key, config, section_name=section, straight_import=True ), reverse=config.reverse_sort, ) from_modules = parsed.imports[section]["from"] if not config.only_sections: from_modules = sorting.sort( config, from_modules, key=lambda key: sorting.module_key(key, config, section_name=section), reverse=config.reverse_sort, ) if config.star_first: star_modules = [] other_modules = [] for module in from_modules: if "*" in parsed.imports[section]["from"][module]: star_modules.append(module) else: other_modules.append(module) from_modules = star_modules + other_modules straight_imports = _with_straight_imports( parsed, config, straight_modules, section, remove_imports, import_type ) from_imports = _with_from_imports( parsed, config, from_modules, section, remove_imports, import_type ) lines_between = [""] * ( config.lines_between_types if from_modules and straight_modules else 0 ) if config.from_first: section_output = from_imports + lines_between + straight_imports else: section_output = straight_imports + lines_between + from_imports if config.force_sort_within_sections: # collapse comments comments_above = [] new_section_output: List[str] = [] for line in section_output: if not line: continue if line.startswith("#"): comments_above.append(line) elif comments_above: new_section_output.append(_LineWithComments(line, comments_above)) comments_above = [] else: new_section_output.append(line) # only_sections options is not imposed if force_sort_within_sections is True new_section_output = sorting.sort( config, new_section_output, key=partial(sorting.section_key, config=config), reverse=config.reverse_sort, ) # uncollapse comments section_output = [] for line in new_section_output: comments = getattr(line, "comments", ()) if comments: section_output.extend(comments) section_output.append(str(line)) section_name = section no_lines_before = section_name in config.no_lines_before if section_output: if section_name in parsed.place_imports: parsed.place_imports[section_name] = section_output continue section_title = config.import_headings.get(section_name.lower(), "") if section_title and section_title not in seen_headings: if config.dedup_headings: seen_headings.add(section_title) section_comment = f"# {section_title}" if section_comment not in parsed.lines_without_imports[0:1]: # pragma: no branch section_output.insert(0, section_comment) section_footer = config.import_footers.get(section_name.lower(), "") if section_footer and section_footer not in seen_headings: if config.dedup_headings: seen_headings.add(section_footer) section_comment_end = f"# {section_footer}" if ( section_comment_end not in parsed.lines_without_imports[-1:] ): # pragma: no branch section_output.append("") # Empty line for black compatibility section_output.append(section_comment_end) if pending_lines_before or not no_lines_before: output += [""] * config.lines_between_sections output += section_output pending_lines_before = False else: pending_lines_before = pending_lines_before or not no_lines_before if config.ensure_newline_before_comments: output = _ensure_newline_before_comment(output) while output and output[-1].strip() == "": output.pop() # pragma: no cover while output and output[0].strip() == "": output.pop(0) if config.formatting_function: output = config.formatting_function( parsed.line_separator.join(output), extension, config ).splitlines() output_at = 0 if parsed.import_index < parsed.original_line_count: output_at = parsed.import_index formatted_output[output_at:0] = output if output: imports_tail = output_at + len(output) while [ character.strip() for character in formatted_output[imports_tail : imports_tail + 1] ] == [""]: formatted_output.pop(imports_tail) if len(formatted_output) > imports_tail: next_construct = "" tail = formatted_output[imports_tail:] for index, line in enumerate(tail): # pragma: no branch should_skip, in_quote, *_ = parse.skip_line( line, in_quote="", index=len(formatted_output), section_comments=config.section_comments, needs_import=False, ) if not should_skip and line.strip(): if ( line.strip().startswith("#") and len(tail) > (index + 1) and tail[index + 1].strip() ): continue next_construct = line break if in_quote: # pragma: no branch next_construct = line break if config.lines_after_imports != -1: lines_after_imports = config.lines_after_imports if config.profile == "black" and extension == "pyi": # special case for black lines_after_imports = 1 formatted_output[imports_tail:0] = ["" for line in range(lines_after_imports)] elif extension != "pyi" and next_construct.startswith(STATEMENT_DECLARATIONS): formatted_output[imports_tail:0] = ["", ""] else: formatted_output[imports_tail:0] = [""] if config.lines_before_imports != -1: lines_before_imports = config.lines_before_imports if config.profile == "black" and extension == "pyi": # special case for black lines_before_imports = 1 formatted_output[:0] = ["" for line in range(lines_before_imports)] if parsed.place_imports: new_out_lines = [] for index, line in enumerate(formatted_output): new_out_lines.append(line) if line in parsed.import_placements: new_out_lines.extend(parsed.place_imports[parsed.import_placements[line]]) if ( len(formatted_output) <= (index + 1) or formatted_output[index + 1].strip() != "" ): new_out_lines.append("") formatted_output = new_out_lines return _output_as_string(formatted_output, parsed.line_separator) # Ignore DeepSource cyclomatic complexity check for this function. It was # already complex when this check was enabled. # skipcq: PY-R1000 def _with_from_imports( parsed: parse.ParsedContent, config: Config, from_modules: Iterable[str], section: str, remove_imports: List[str], import_type: str, ) -> List[str]: output: List[str] = [] for module in from_modules: if module in remove_imports: continue import_start = f"from {module} {import_type} " from_imports = list(parsed.imports[section]["from"][module]) if ( not config.no_inline_sort or (config.force_single_line and module not in config.single_line_exclusions) ) and not config.only_sections: from_imports = sorting.sort( config, from_imports, key=lambda key: sorting.module_key( key, config, True, config.force_alphabetical_sort_within_sections, section_name=section, ), reverse=config.reverse_sort, ) if remove_imports: from_imports = [ line for line in from_imports if f"{module}.{line}" not in remove_imports ] sub_modules = [f"{module}.{from_import}" for from_import in from_imports] as_imports = { from_import: [ f"{from_import} as {as_module}" for as_module in parsed.as_map["from"][sub_module] ] for from_import, sub_module in zip(from_imports, sub_modules) if sub_module in parsed.as_map["from"] } if config.combine_as_imports and not ("*" in from_imports and config.combine_star): if not config.no_inline_sort: for as_import in as_imports: if not config.only_sections: as_imports[as_import] = sorting.sort(config, as_imports[as_import]) for from_import in copy.copy(from_imports): if from_import in as_imports: idx = from_imports.index(from_import) if parsed.imports[section]["from"][module][from_import]: from_imports[(idx + 1) : (idx + 1)] = as_imports.pop(from_import) else: from_imports[idx : (idx + 1)] = as_imports.pop(from_import) only_show_as_imports = False comments = parsed.categorized_comments["from"].pop(module, ()) above_comments = parsed.categorized_comments["above"]["from"].pop(module, None) while from_imports: if above_comments: output.extend(above_comments) above_comments = None if "*" in from_imports and config.combine_star: import_statement = wrap.line( with_comments( _with_star_comments(parsed, module, list(comments or ())), f"{import_start}*", removed=config.ignore_comments, comment_prefix=config.comment_prefix, ), parsed.line_separator, config, ) from_imports = [ from_import for from_import in from_imports if from_import in as_imports ] only_show_as_imports = True elif config.force_single_line and module not in config.single_line_exclusions: import_statement = "" while from_imports: from_import = from_imports.pop(0) single_import_line = with_comments( comments, import_start + from_import, removed=config.ignore_comments, comment_prefix=config.comment_prefix, ) comment = ( parsed.categorized_comments["nested"].get(module, {}).pop(from_import, None) ) if comment: single_import_line += ( f"{(comments and ';') or config.comment_prefix} " f"{comment}" ) if from_import in as_imports: if ( parsed.imports[section]["from"][module][from_import] and not only_show_as_imports ): output.append( wrap.line(single_import_line, parsed.line_separator, config) ) from_comments = parsed.categorized_comments["straight"].get( f"{module}.{from_import}" ) if not config.only_sections: output.extend( with_comments( from_comments, wrap.line( import_start + as_import, parsed.line_separator, config ), removed=config.ignore_comments, comment_prefix=config.comment_prefix, ) for as_import in sorting.sort(config, as_imports[from_import]) ) else: output.extend( with_comments( from_comments, wrap.line( import_start + as_import, parsed.line_separator, config ), removed=config.ignore_comments, comment_prefix=config.comment_prefix, ) for as_import in as_imports[from_import] ) else: output.append(wrap.line(single_import_line, parsed.line_separator, config)) comments = None else: while from_imports and from_imports[0] in as_imports: from_import = from_imports.pop(0) if not config.only_sections: as_imports[from_import] = sorting.sort(config, as_imports[from_import]) from_comments = ( parsed.categorized_comments["straight"].get(f"{module}.{from_import}") or [] ) if ( parsed.imports[section]["from"][module][from_import] and not only_show_as_imports ): specific_comment = ( parsed.categorized_comments["nested"] .get(module, {}) .pop(from_import, None) ) if specific_comment: from_comments.append(specific_comment) output.append( wrap.line( with_comments( from_comments, import_start + from_import, removed=config.ignore_comments, comment_prefix=config.comment_prefix, ), parsed.line_separator, config, ) ) from_comments = [] for as_import in as_imports[from_import]: specific_comment = ( parsed.categorized_comments["nested"] .get(module, {}) .pop(as_import, None) ) if specific_comment: from_comments.append(specific_comment) output.append( wrap.line( with_comments( from_comments, import_start + as_import, removed=config.ignore_comments, comment_prefix=config.comment_prefix, ), parsed.line_separator, config, ) ) from_comments = [] if "*" in from_imports: output.append( with_comments( _with_star_comments(parsed, module, []), f"{import_start}*", removed=config.ignore_comments, comment_prefix=config.comment_prefix, ) ) from_imports.remove("*") for from_import in copy.copy(from_imports): comment = ( parsed.categorized_comments["nested"].get(module, {}).pop(from_import, None) ) if comment: from_imports.remove(from_import) if from_imports: use_comments = [] else: use_comments = comments comments = None single_import_line = with_comments( use_comments, import_start + from_import, removed=config.ignore_comments, comment_prefix=config.comment_prefix, ) single_import_line += ( f"{(use_comments and ';') or config.comment_prefix} " f"{comment}" ) output.append(wrap.line(single_import_line, parsed.line_separator, config)) from_import_section = [] while from_imports and ( from_imports[0] not in as_imports or ( config.combine_as_imports and parsed.imports[section]["from"][module][from_import] ) ): from_import_section.append(from_imports.pop(0)) if config.combine_as_imports: comments = (comments or []) + list( parsed.categorized_comments["from"].pop(f"{module}.__combined_as__", ()) ) import_statement = with_comments( comments, import_start + (", ").join(from_import_section), removed=config.ignore_comments, comment_prefix=config.comment_prefix, ) if not from_import_section: import_statement = "" do_multiline_reformat = False force_grid_wrap = config.force_grid_wrap if force_grid_wrap and len(from_import_section) >= force_grid_wrap: do_multiline_reformat = True if len(import_statement) > config.line_length and len(from_import_section) > 1: do_multiline_reformat = True # If line too long AND have imports AND we are # NOT using GRID or VERTICAL wrap modes if ( len(import_statement) > config.line_length and len(from_import_section) > 0 and config.multi_line_output not in (wrap.Modes.GRID, wrap.Modes.VERTICAL) # type: ignore ): do_multiline_reformat = True if ( import_statement and config.split_on_trailing_comma and module in parsed.trailing_commas ): import_statement = wrap.import_statement( import_start=import_start, from_imports=from_import_section, comments=comments, line_separator=parsed.line_separator, config=config, explode=True, ) elif do_multiline_reformat: import_statement = wrap.import_statement( import_start=import_start, from_imports=from_import_section, comments=comments, line_separator=parsed.line_separator, config=config, ) if config.multi_line_output == wrap.Modes.GRID: # type: ignore other_import_statement = wrap.import_statement( import_start=import_start, from_imports=from_import_section, comments=comments, line_separator=parsed.line_separator, config=config, multi_line_output=wrap.Modes.VERTICAL_GRID, # type: ignore ) if ( max( len(import_line) for import_line in import_statement.split(parsed.line_separator) ) > config.line_length ): import_statement = other_import_statement elif len(import_statement) > config.line_length: import_statement = wrap.line(import_statement, parsed.line_separator, config) if import_statement: output.append(import_statement) return output def _with_straight_imports( parsed: parse.ParsedContent, config: Config, straight_modules: Iterable[str], section: str, remove_imports: List[str], import_type: str, ) -> List[str]: output: List[str] = [] as_imports = any(module in parsed.as_map["straight"] for module in straight_modules) # combine_straight_imports only works for bare imports, 'as' imports not included if config.combine_straight_imports and not as_imports: if not straight_modules: return [] above_comments: List[str] = [] inline_comments: List[str] = [] for module in straight_modules: if module in parsed.categorized_comments["above"]["straight"]: above_comments.extend(parsed.categorized_comments["above"]["straight"].pop(module)) if module in parsed.categorized_comments["straight"]: inline_comments.extend(parsed.categorized_comments["straight"][module]) combined_straight_imports = ", ".join(straight_modules) if inline_comments: combined_inline_comments = " ".join(inline_comments) else: combined_inline_comments = "" output.extend(above_comments) if combined_inline_comments: output.append( f"{import_type} {combined_straight_imports} # {combined_inline_comments}" ) else: output.append(f"{import_type} {combined_straight_imports}") return output for module in straight_modules: if module in remove_imports: continue import_definition = [] if module in parsed.as_map["straight"]: if parsed.imports[section]["straight"][module]: import_definition.append((f"{import_type} {module}", module)) import_definition.extend( (f"{import_type} {module} as {as_import}", f"{module} as {as_import}") for as_import in parsed.as_map["straight"][module] ) else: import_definition.append((f"{import_type} {module}", module)) comments_above = parsed.categorized_comments["above"]["straight"].pop(module, None) if comments_above: output.extend(comments_above) output.extend( with_comments( parsed.categorized_comments["straight"].get(imodule), idef, removed=config.ignore_comments, comment_prefix=config.comment_prefix, ) for idef, imodule in import_definition ) return output def _output_as_string(lines: List[str], line_separator: str) -> str: return line_separator.join(_normalize_empty_lines(lines)) def _normalize_empty_lines(lines: List[str]) -> List[str]: while lines and lines[-1].strip() == "": lines.pop(-1) lines.append("") return lines class _LineWithComments(str): comments: List[str] def __new__( cls: Type["_LineWithComments"], value: Any, comments: List[str] ) -> "_LineWithComments": instance = super().__new__(cls, value) instance.comments = comments return instance def _ensure_newline_before_comment(output: List[str]) -> List[str]: new_output: List[str] = [] def is_comment(line: Optional[str]) -> bool: return line.startswith("#") if line else False for line, prev_line in zip(output, [None, *output]): if is_comment(line) and prev_line != "" and not is_comment(prev_line): new_output.append("") new_output.append(line) return new_output def _with_star_comments(parsed: parse.ParsedContent, module: str, comments: List[str]) -> List[str]: star_comment = parsed.categorized_comments["nested"].get(module, {}).pop("*", None) if star_comment: return [*comments, star_comment] return comments isort-6.0.1/isort/parse.py0000644000000000000000000006174413615410400012436 0ustar00"""Defines parsing functions used by isort for parsing import definitions""" import re from collections import OrderedDict, defaultdict from functools import partial from itertools import chain from typing import TYPE_CHECKING, Any, Dict, List, NamedTuple, Optional, Set, Tuple from warnings import warn from . import place from .comments import parse as parse_comments from .exceptions import MissingSection from .settings import DEFAULT_CONFIG, Config if TYPE_CHECKING: from mypy_extensions import TypedDict CommentsAboveDict = TypedDict( "CommentsAboveDict", {"straight": Dict[str, Any], "from": Dict[str, Any]} ) CommentsDict = TypedDict( "CommentsDict", { "from": Dict[str, Any], "straight": Dict[str, Any], "nested": Dict[str, Any], "above": CommentsAboveDict, }, ) def _infer_line_separator(contents: str) -> str: if "\r\n" in contents: return "\r\n" if "\r" in contents: return "\r" return "\n" def normalize_line(raw_line: str) -> Tuple[str, str]: """Normalizes import related statements in the provided line. Returns (normalized_line: str, raw_line: str) """ line = re.sub(r"from(\.+)cimport ", r"from \g<1> cimport ", raw_line) line = re.sub(r"from(\.+)import ", r"from \g<1> import ", line) line = line.replace("import*", "import *") line = re.sub(r" (\.+)import ", r" \g<1> import ", line) line = re.sub(r" (\.+)cimport ", r" \g<1> cimport ", line) line = line.replace("\t", " ") return line, raw_line def import_type(line: str, config: Config = DEFAULT_CONFIG) -> Optional[str]: """If the current line is an import line it will return its type (from or straight)""" if config.honor_noqa and line.lower().rstrip().endswith("noqa"): return None if "isort:skip" in line or "isort: skip" in line or "isort: split" in line: return None if line.startswith(("import ", "cimport ")): return "straight" if line.startswith("from "): return "from" return None def strip_syntax(import_string: str) -> str: import_string = import_string.replace("_import", "[[i]]") import_string = import_string.replace("_cimport", "[[ci]]") for remove_syntax in ["\\", "(", ")", ","]: import_string = import_string.replace(remove_syntax, " ") import_list = import_string.split() for key in ("from", "import", "cimport"): if key in import_list: import_list.remove(key) import_string = " ".join(import_list) import_string = import_string.replace("[[i]]", "_import") import_string = import_string.replace("[[ci]]", "_cimport") return import_string.replace("{ ", "{|").replace(" }", "|}") def skip_line( line: str, in_quote: str, index: int, section_comments: Tuple[str, ...], needs_import: bool = True, ) -> Tuple[bool, str]: """Determine if a given line should be skipped. Returns back a tuple containing: (skip_line: bool, in_quote: str,) """ should_skip = bool(in_quote) if '"' in line or "'" in line: char_index = 0 while char_index < len(line): if line[char_index] == "\\": char_index += 1 elif in_quote: if line[char_index : char_index + len(in_quote)] == in_quote: in_quote = "" elif line[char_index] in ("'", '"'): long_quote = line[char_index : char_index + 3] if long_quote in ('"""', "'''"): in_quote = long_quote char_index += 2 else: in_quote = line[char_index] elif line[char_index] == "#": break char_index += 1 if ";" in line.split("#")[0] and needs_import: for part in (part.strip() for part in line.split(";")): if ( part and not part.startswith("from ") and not part.startswith(("import ", "cimport ")) ): should_skip = True return (bool(should_skip or in_quote), in_quote) class ParsedContent(NamedTuple): in_lines: List[str] lines_without_imports: List[str] import_index: int place_imports: Dict[str, List[str]] import_placements: Dict[str, str] as_map: Dict[str, Dict[str, List[str]]] imports: Dict[str, Dict[str, Any]] categorized_comments: "CommentsDict" change_count: int original_line_count: int line_separator: str sections: Any verbose_output: List[str] trailing_commas: Set[str] def file_contents(contents: str, config: Config = DEFAULT_CONFIG) -> ParsedContent: """Parses a python file taking out and categorizing imports.""" line_separator: str = config.line_ending or _infer_line_separator(contents) in_lines = contents.splitlines() if contents and contents[-1] in ("\n", "\r"): in_lines.append("") out_lines = [] original_line_count = len(in_lines) if config.old_finders: from .deprecated.finders import FindersManager finder = FindersManager(config=config).find else: finder = partial(place.module, config=config) line_count = len(in_lines) place_imports: Dict[str, List[str]] = {} import_placements: Dict[str, str] = {} as_map: Dict[str, Dict[str, List[str]]] = { "straight": defaultdict(list), "from": defaultdict(list), } imports: OrderedDict[str, Dict[str, Any]] = OrderedDict() verbose_output: List[str] = [] for section in chain(config.sections, config.forced_separate): imports[section] = {"straight": OrderedDict(), "from": OrderedDict()} categorized_comments: CommentsDict = { "from": {}, "straight": {}, "nested": {}, "above": {"straight": {}, "from": {}}, } trailing_commas: Set[str] = set() index = 0 import_index = -1 in_quote = "" while index < line_count: line = in_lines[index] index += 1 statement_index = index (skipping_line, in_quote) = skip_line( line, in_quote=in_quote, index=index, section_comments=config.section_comments ) if ( line in config.section_comments or line in config.section_comments_end ) and not skipping_line: if import_index == -1: # pragma: no branch import_index = index - 1 continue if "isort:imports-" in line and line.startswith("#"): section = line.split("isort:imports-")[-1].split()[0].upper() place_imports[section] = [] import_placements[line] = section elif "isort: imports-" in line and line.startswith("#"): section = line.split("isort: imports-")[-1].split()[0].upper() place_imports[section] = [] import_placements[line] = section if skipping_line: out_lines.append(line) continue lstripped_line = line.lstrip() if ( config.float_to_top and import_index == -1 and line and not in_quote and not lstripped_line.startswith("#") and not lstripped_line.startswith("'''") and not lstripped_line.startswith('"""') ): if not lstripped_line.startswith("import") and not lstripped_line.startswith("from"): import_index = index - 1 while import_index and not in_lines[import_index - 1]: import_index -= 1 else: commentless = line.split("#", 1)[0].strip() if ( ("isort:skip" in line or "isort: skip" in line) and "(" in commentless and ")" not in commentless ): import_index = index starting_line = line while "isort:skip" in starting_line or "isort: skip" in starting_line: commentless = starting_line.split("#", 1)[0] if ( "(" in commentless and not commentless.rstrip().endswith(")") and import_index < line_count ): while import_index < line_count and not commentless.rstrip().endswith( ")" ): commentless = in_lines[import_index].split("#", 1)[0] import_index += 1 else: import_index += 1 if import_index >= line_count: break starting_line = in_lines[import_index] line, *end_of_line_comment = line.split("#", 1) if ";" in line: statements = [line.strip() for line in line.split(";")] else: statements = [line] if end_of_line_comment: statements[-1] = f"{statements[-1]}#{end_of_line_comment[0]}" for statement in statements: line, raw_line = normalize_line(statement) type_of_import = import_type(line, config) or "" raw_lines = [raw_line] if not type_of_import: out_lines.append(raw_line) continue if import_index == -1: import_index = index - 1 nested_comments = {} import_string, comment = parse_comments(line) comments = [comment] if comment else [] line_parts = [part for part in strip_syntax(import_string).strip().split(" ") if part] if type_of_import == "from" and len(line_parts) == 2 and comments: nested_comments[line_parts[-1]] = comments[0] if "(" in line.split("#", 1)[0] and index < line_count: while not line.split("#")[0].strip().endswith(")") and index < line_count: line, new_comment = parse_comments(in_lines[index]) index += 1 if new_comment: comments.append(new_comment) stripped_line = strip_syntax(line).strip() if ( type_of_import == "from" and stripped_line and " " not in stripped_line.replace(" as ", "") and new_comment ): nested_comments[stripped_line] = comments[-1] import_string += line_separator + line raw_lines.append(line) else: while line.strip().endswith("\\"): line, new_comment = parse_comments(in_lines[index]) line = line.lstrip() index += 1 if new_comment: comments.append(new_comment) # Still need to check for parentheses after an escaped line if ( "(" in line.split("#")[0] and ")" not in line.split("#")[0] and index < line_count ): stripped_line = strip_syntax(line).strip() if ( type_of_import == "from" and stripped_line and " " not in stripped_line.replace(" as ", "") and new_comment ): nested_comments[stripped_line] = comments[-1] import_string += line_separator + line raw_lines.append(line) while not line.split("#")[0].strip().endswith(")") and index < line_count: line, new_comment = parse_comments(in_lines[index]) index += 1 if new_comment: comments.append(new_comment) stripped_line = strip_syntax(line).strip() if ( type_of_import == "from" and stripped_line and " " not in stripped_line.replace(" as ", "") and new_comment ): nested_comments[stripped_line] = comments[-1] import_string += line_separator + line raw_lines.append(line) stripped_line = strip_syntax(line).strip() if ( type_of_import == "from" and stripped_line and " " not in stripped_line.replace(" as ", "") and new_comment ): nested_comments[stripped_line] = comments[-1] if import_string.strip().endswith( (" import", " cimport") ) or line.strip().startswith(("import ", "cimport ")): import_string += line_separator + line else: import_string = import_string.rstrip().rstrip("\\") + " " + line.lstrip() if type_of_import == "from": cimports: bool import_string = ( import_string.replace("import(", "import (") .replace("\\", " ") .replace("\n", " ") ) if "import " not in import_string: out_lines.extend(raw_lines) continue if " cimport " in import_string: parts = import_string.split(" cimport ") cimports = True else: parts = import_string.split(" import ") cimports = False from_import = parts[0].split(" ") import_string = (" cimport " if cimports else " import ").join( [from_import[0] + " " + "".join(from_import[1:])] + parts[1:] ) just_imports = [ item.replace("{|", "{ ").replace("|}", " }") for item in strip_syntax(import_string).split() ] attach_comments_to: Optional[List[Any]] = None direct_imports = just_imports[1:] straight_import = True top_level_module = "" if "as" in just_imports and (just_imports.index("as") + 1) < len(just_imports): straight_import = False while "as" in just_imports: nested_module = None as_index = just_imports.index("as") if type_of_import == "from": nested_module = just_imports[as_index - 1] top_level_module = just_imports[0] module = top_level_module + "." + nested_module as_name = just_imports[as_index + 1] direct_imports.remove(nested_module) direct_imports.remove(as_name) direct_imports.remove("as") if nested_module == as_name and config.remove_redundant_aliases: pass elif as_name not in as_map["from"][module]: # pragma: no branch as_map["from"][module].append(as_name) full_name = f"{nested_module} as {as_name}" associated_comment = nested_comments.get(full_name) if associated_comment: categorized_comments["nested"].setdefault(top_level_module, {})[ full_name ] = associated_comment if associated_comment in comments: # pragma: no branch comments.pop(comments.index(associated_comment)) else: module = just_imports[as_index - 1] as_name = just_imports[as_index + 1] if module == as_name and config.remove_redundant_aliases: pass elif as_name not in as_map["straight"][module]: as_map["straight"][module].append(as_name) if comments and attach_comments_to is None: if nested_module and config.combine_as_imports: attach_comments_to = categorized_comments["from"].setdefault( f"{top_level_module}.__combined_as__", [] ) else: if type_of_import == "from" or ( config.remove_redundant_aliases and as_name == module.split(".")[-1] ): attach_comments_to = categorized_comments["straight"].setdefault( module, [] ) else: attach_comments_to = categorized_comments["straight"].setdefault( f"{module} as {as_name}", [] ) del just_imports[as_index : as_index + 2] if type_of_import == "from": import_from = just_imports.pop(0) placed_module = finder(import_from) if config.verbose and not config.only_modified: print(f"from-type place_module for {import_from} returned {placed_module}") elif config.verbose: verbose_output.append( f"from-type place_module for {import_from} returned {placed_module}" ) if placed_module == "": warn( f"could not place module {import_from} of line {line} --" " Do you need to define a default section?", stacklevel=2, ) if placed_module and placed_module not in imports: raise MissingSection(import_module=import_from, section=placed_module) root = imports[placed_module][type_of_import] # type: ignore for import_name in just_imports: associated_comment = nested_comments.get(import_name) if associated_comment: categorized_comments["nested"].setdefault(import_from, {})[ import_name ] = associated_comment if associated_comment in comments: # pragma: no branch comments.pop(comments.index(associated_comment)) if ( config.force_single_line and comments and attach_comments_to is None and len(just_imports) == 1 ): nested_from_comments = categorized_comments["nested"].setdefault( import_from, {} ) existing_comment = nested_from_comments.get(just_imports[0], "") nested_from_comments[just_imports[0]] = ( f"{existing_comment}{'; ' if existing_comment else ''}{'; '.join(comments)}" ) comments = [] if comments and attach_comments_to is None: attach_comments_to = categorized_comments["from"].setdefault(import_from, []) if len(out_lines) > max(import_index, 1) - 1: last = out_lines[-1].rstrip() if out_lines else "" while ( last.startswith("#") and not last.endswith('"""') and not last.endswith("'''") and "isort:imports-" not in last and "isort: imports-" not in last and not config.treat_all_comments_as_code and last.strip() not in config.treat_comments_as_code ): categorized_comments["above"]["from"].setdefault(import_from, []).insert( 0, out_lines.pop(-1) ) if out_lines: last = out_lines[-1].rstrip() else: last = "" if statement_index - 1 == import_index: # pragma: no cover import_index -= len( categorized_comments["above"]["from"].get(import_from, []) ) if import_from not in root: root[import_from] = OrderedDict( (module, module in direct_imports) for module in just_imports ) else: root[import_from].update( (module, root[import_from].get(module, False) or module in direct_imports) for module in just_imports ) if comments and attach_comments_to is not None: attach_comments_to.extend(comments) if ( just_imports and just_imports[-1] and "," in import_string.split(just_imports[-1])[-1] ): trailing_commas.add(import_from) else: if comments and attach_comments_to is not None: attach_comments_to.extend(comments) comments = [] for module in just_imports: if comments: categorized_comments["straight"][module] = comments comments = [] if len(out_lines) > max(import_index, +1, 1) - 1: last = out_lines[-1].rstrip() if out_lines else "" while ( last.startswith("#") and not last.endswith('"""') and not last.endswith("'''") and "isort:imports-" not in last and "isort: imports-" not in last and not config.treat_all_comments_as_code and last.strip() not in config.treat_comments_as_code ): categorized_comments["above"]["straight"].setdefault(module, []).insert( 0, out_lines.pop(-1) ) if out_lines: last = out_lines[-1].rstrip() else: last = "" if index - 1 == import_index: import_index -= len( categorized_comments["above"]["straight"].get(module, []) ) placed_module = finder(module) if config.verbose and not config.only_modified: print(f"else-type place_module for {module} returned {placed_module}") elif config.verbose: verbose_output.append( f"else-type place_module for {module} returned {placed_module}" ) if placed_module == "": warn( f"could not place module {module} of line {line} --" " Do you need to define a default section?", stacklevel=2, ) imports.setdefault("", {"straight": OrderedDict(), "from": OrderedDict()}) if placed_module and placed_module not in imports: raise MissingSection(import_module=module, section=placed_module) straight_import |= imports[placed_module][type_of_import].get( # type: ignore module, False ) imports[placed_module][type_of_import][module] = straight_import # type: ignore change_count = len(out_lines) - original_line_count return ParsedContent( in_lines=in_lines, lines_without_imports=out_lines, import_index=import_index, place_imports=place_imports, import_placements=import_placements, as_map=as_map, imports=imports, categorized_comments=categorized_comments, change_count=change_count, original_line_count=original_line_count, line_separator=line_separator, sections=config.sections, verbose_output=verbose_output, trailing_commas=trailing_commas, ) isort-6.0.1/isort/place.py0000644000000000000000000001206313615410400012376 0ustar00"""Contains all logic related to placing an import within a certain section.""" import importlib from fnmatch import fnmatch from functools import lru_cache from pathlib import Path from typing import FrozenSet, Iterable, Optional, Tuple from isort import sections from isort.settings import DEFAULT_CONFIG, Config from isort.utils import exists_case_sensitive LOCAL = "LOCALFOLDER" def module(name: str, config: Config = DEFAULT_CONFIG) -> str: """Returns the section placement for the given module name.""" return module_with_reason(name, config)[0] @lru_cache(maxsize=1000) def module_with_reason(name: str, config: Config = DEFAULT_CONFIG) -> Tuple[str, str]: """Returns the section placement for the given module name alongside the reasoning.""" return ( _forced_separate(name, config) or _local(name, config) or _known_pattern(name, config) or _src_path(name, config) or (config.default_section, "Default option in Config or universal default.") ) def _forced_separate(name: str, config: Config) -> Optional[Tuple[str, str]]: for forced_separate in config.forced_separate: # Ensure all forced_separate patterns will match to end of string path_glob = forced_separate if not forced_separate.endswith("*"): path_glob = f"{forced_separate}*" if fnmatch(name, path_glob) or fnmatch(name, "." + path_glob): return (forced_separate, f"Matched forced_separate ({forced_separate}) config value.") return None def _local(name: str, config: Config) -> Optional[Tuple[str, str]]: if name.startswith("."): return (LOCAL, "Module name started with a dot.") return None def _known_pattern(name: str, config: Config) -> Optional[Tuple[str, str]]: parts = name.split(".") module_names_to_check = (".".join(parts[:first_k]) for first_k in range(len(parts), 0, -1)) for module_name_to_check in module_names_to_check: for pattern, placement in config.known_patterns: if placement in config.sections and pattern.match(module_name_to_check): return (placement, f"Matched configured known pattern {pattern}") return None def _src_path( name: str, config: Config, src_paths: Optional[Iterable[Path]] = None, prefix: Tuple[str, ...] = (), ) -> Optional[Tuple[str, str]]: if src_paths is None: src_paths = config.src_paths root_module_name, *nested_module = name.split(".", 1) new_prefix = (*prefix, root_module_name) namespace = ".".join(new_prefix) for src_path in src_paths: module_path = (src_path / root_module_name).resolve() if not prefix and not module_path.is_dir() and src_path.name == root_module_name: module_path = src_path.resolve() if nested_module and ( namespace in config.namespace_packages or ( config.auto_identify_namespace_packages and _is_namespace_package(module_path, config.supported_extensions) ) ): return _src_path(nested_module[0], config, (module_path,), new_prefix) if ( _is_module(module_path) or _is_package(module_path) or _src_path_is_module(src_path, root_module_name) ): return (sections.FIRSTPARTY, f"Found in one of the configured src_paths: {src_path}.") return None def _is_module(path: Path) -> bool: return ( exists_case_sensitive(str(path.with_suffix(".py"))) or any( exists_case_sensitive(str(path.with_suffix(ext_suffix))) for ext_suffix in importlib.machinery.EXTENSION_SUFFIXES ) or exists_case_sensitive(str(path / "__init__.py")) ) def _is_package(path: Path) -> bool: return exists_case_sensitive(str(path)) and path.is_dir() def _is_namespace_package(path: Path, src_extensions: FrozenSet[str]) -> bool: if not _is_package(path): return False init_file = path / "__init__.py" if not init_file.exists(): filenames = [ filepath for filepath in path.iterdir() if filepath.suffix.lstrip(".") in src_extensions or filepath.name.lower() in ("setup.cfg", "pyproject.toml") ] if filenames: return False else: with init_file.open("rb") as open_init_file: file_start = open_init_file.read(4096) if ( b"__import__('pkg_resources').declare_namespace(__name__)" not in file_start and b'__import__("pkg_resources").declare_namespace(__name__)' not in file_start and b"__path__ = __import__('pkgutil').extend_path(__path__, __name__)" not in file_start and b'__path__ = __import__("pkgutil").extend_path(__path__, __name__)' not in file_start ): return False return True def _src_path_is_module(src_path: Path, module_name: str) -> bool: return ( module_name == src_path.name and src_path.is_dir() and exists_case_sensitive(str(src_path)) ) isort-6.0.1/isort/profiles.py0000644000000000000000000000437213615410400013141 0ustar00"""Common profiles are defined here to be easily used within a project using --profile {name}""" from typing import Any, Dict black = { "multi_line_output": 3, "include_trailing_comma": True, "split_on_trailing_comma": True, "force_grid_wrap": 0, "use_parentheses": True, "ensure_newline_before_comments": True, "line_length": 88, } django = { "combine_as_imports": True, "include_trailing_comma": True, "multi_line_output": 5, "line_length": 79, } pycharm = { "multi_line_output": 3, "force_grid_wrap": 2, "lines_after_imports": 2, } google = { "force_single_line": True, "force_sort_within_sections": True, "lexicographical": True, "line_length": 1000, "single_line_exclusions": ( "collections.abc", "six.moves", "typing", "typing_extensions", ), "order_by_type": False, "group_by_package": True, } open_stack = { "force_single_line": True, "force_sort_within_sections": True, "lexicographical": True, } plone = black.copy() plone.update( { "force_alphabetical_sort": True, "force_single_line": True, "lines_after_imports": 2, } ) attrs = { "atomic": True, "force_grid_wrap": 0, "include_trailing_comma": True, "lines_after_imports": 2, "lines_between_types": 1, "multi_line_output": 3, "use_parentheses": True, } hug = { "multi_line_output": 3, "include_trailing_comma": True, "force_grid_wrap": 0, "use_parentheses": True, "line_length": 100, } wemake = { "multi_line_output": 3, "include_trailing_comma": True, "use_parentheses": True, "line_length": 80, } appnexus = { **black, "force_sort_within_sections": True, "order_by_type": False, "case_sensitive": False, "reverse_relative": True, "sort_relative_in_force_sorted_sections": True, "sections": ["FUTURE", "STDLIB", "THIRDPARTY", "FIRSTPARTY", "APPLICATION", "LOCALFOLDER"], "no_lines_before": "LOCALFOLDER", } profiles: Dict[str, Dict[str, Any]] = { "black": black, "django": django, "pycharm": pycharm, "google": google, "open_stack": open_stack, "plone": plone, "attrs": attrs, "hug": hug, "wemake": wemake, "appnexus": appnexus, } isort-6.0.1/isort/py.typed0000644000000000000000000000000013615410400012423 0ustar00isort-6.0.1/isort/pylama_isort.py0000644000000000000000000000243413615410400014016 0ustar00import os import sys from contextlib import contextmanager from typing import Any, Dict, Iterator, List, Optional from pylama.lint import Linter as BaseLinter # type: ignore from isort.exceptions import FileSkipped from . import api @contextmanager def suppress_stdout() -> Iterator[None]: stdout = sys.stdout with open(os.devnull, "w") as devnull: sys.stdout = devnull yield sys.stdout = stdout class Linter(BaseLinter): # type: ignore def allow(self, path: str) -> bool: """Determine if this path should be linted.""" return path.endswith(".py") def run( self, path: str, params: Optional[Dict[str, Any]] = None, **meta: Any ) -> List[Dict[str, Any]]: """Lint the file. Return an array of error dicts if appropriate.""" with suppress_stdout(): try: if not api.check_file(path, disregard_skip=False, **params or {}): return [ { "lnum": 0, "col": 0, "text": "Incorrectly sorted imports.", "type": "ISORT", } ] except FileSkipped: pass return [] isort-6.0.1/isort/sections.py0000644000000000000000000000045213615410400013140 0ustar00"""Defines all sections isort uses by default""" from typing import Tuple FUTURE: str = "FUTURE" STDLIB: str = "STDLIB" THIRDPARTY: str = "THIRDPARTY" FIRSTPARTY: str = "FIRSTPARTY" LOCALFOLDER: str = "LOCALFOLDER" DEFAULT: Tuple[str, ...] = (FUTURE, STDLIB, THIRDPARTY, FIRSTPARTY, LOCALFOLDER) isort-6.0.1/isort/settings.py0000644000000000000000000010542013615410400013152 0ustar00"""isort/settings.py. Defines how the default settings for isort should be loaded """ import configparser import fnmatch import os import posixpath import re import stat import subprocess # nosec: Needed for gitignore support. import sys from dataclasses import dataclass, field from pathlib import Path from typing import ( TYPE_CHECKING, Any, Callable, Dict, FrozenSet, Iterable, List, Optional, Pattern, Set, Tuple, Type, Union, ) from warnings import warn from . import sorting, stdlibs from .exceptions import ( FormattingPluginDoesNotExist, InvalidSettingsPath, ProfileDoesNotExist, SortingFunctionDoesNotExist, UnsupportedSettings, ) from .profiles import profiles as profiles from .sections import DEFAULT as SECTION_DEFAULTS from .sections import FIRSTPARTY, FUTURE, LOCALFOLDER, STDLIB, THIRDPARTY from .utils import Trie from .wrap_modes import WrapModes from .wrap_modes import from_string as wrap_mode_from_string if TYPE_CHECKING: tomllib: Any else: if sys.version_info >= (3, 11): import tomllib else: from ._vendored import tomli as tomllib _SHEBANG_RE = re.compile(rb"^#!.*\bpython[23w]?\b") CYTHON_EXTENSIONS = frozenset({"pyx", "pxd"}) SUPPORTED_EXTENSIONS = frozenset({"py", "pyi", *CYTHON_EXTENSIONS}) BLOCKED_EXTENSIONS = frozenset({"pex"}) FILE_SKIP_COMMENTS: Tuple[str, ...] = ( "isort:" + "skip_file", "isort: " + "skip_file", ) # Concatenated to avoid this file being skipped MAX_CONFIG_SEARCH_DEPTH: int = 25 # The number of parent directories to for a config file within STOP_CONFIG_SEARCH_ON_DIRS: Tuple[str, ...] = (".git", ".hg") VALID_PY_TARGETS: Tuple[str, ...] = tuple( target.replace("py", "") for target in dir(stdlibs) if not target.startswith("_") ) CONFIG_SOURCES: Tuple[str, ...] = ( ".isort.cfg", "pyproject.toml", "setup.cfg", "tox.ini", ".editorconfig", ) DEFAULT_SKIP: FrozenSet[str] = frozenset( { ".venv", "venv", ".tox", ".eggs", ".git", ".hg", ".mypy_cache", ".nox", ".svn", ".bzr", "_build", "buck-out", "build", "dist", ".pants.d", ".direnv", "node_modules", "__pypackages__", ".pytype", } ) CONFIG_SECTIONS: Dict[str, Tuple[str, ...]] = { ".isort.cfg": ("settings", "isort"), "pyproject.toml": ("tool.isort",), "setup.cfg": ("isort", "tool:isort"), "tox.ini": ("isort", "tool:isort"), ".editorconfig": ("*", "*.py", "**.py", "*.{py}"), } FALLBACK_CONFIG_SECTIONS: Tuple[str, ...] = ("isort", "tool:isort", "tool.isort") IMPORT_HEADING_PREFIX = "import_heading_" IMPORT_FOOTER_PREFIX = "import_footer_" KNOWN_PREFIX = "known_" KNOWN_SECTION_MAPPING: Dict[str, str] = { STDLIB: "STANDARD_LIBRARY", FUTURE: "FUTURE_LIBRARY", FIRSTPARTY: "FIRST_PARTY", THIRDPARTY: "THIRD_PARTY", LOCALFOLDER: "LOCAL_FOLDER", } RUNTIME_SOURCE = "runtime" DEPRECATED_SETTINGS = ("not_skip", "keep_direct_and_as_imports") _STR_BOOLEAN_MAPPING = { "y": True, "yes": True, "t": True, "on": True, "1": True, "true": True, "n": False, "no": False, "f": False, "off": False, "0": False, "false": False, } @dataclass(frozen=True) class _Config: """Defines the data schema and defaults used for isort configuration. NOTE: known lists, such as known_standard_library, are intentionally not complete as they are dynamically determined later on. """ py_version: str = "3" force_to_top: FrozenSet[str] = frozenset() skip: FrozenSet[str] = DEFAULT_SKIP extend_skip: FrozenSet[str] = frozenset() skip_glob: FrozenSet[str] = frozenset() extend_skip_glob: FrozenSet[str] = frozenset() skip_gitignore: bool = False line_length: int = 79 wrap_length: int = 0 line_ending: str = "" sections: Tuple[str, ...] = SECTION_DEFAULTS no_sections: bool = False known_future_library: FrozenSet[str] = frozenset(("__future__",)) known_third_party: FrozenSet[str] = frozenset() known_first_party: FrozenSet[str] = frozenset() known_local_folder: FrozenSet[str] = frozenset() known_standard_library: FrozenSet[str] = frozenset() extra_standard_library: FrozenSet[str] = frozenset() known_other: Dict[str, FrozenSet[str]] = field(default_factory=dict) multi_line_output: WrapModes = WrapModes.GRID # type: ignore forced_separate: Tuple[str, ...] = () indent: str = " " * 4 comment_prefix: str = " #" length_sort: bool = False length_sort_straight: bool = False length_sort_sections: FrozenSet[str] = frozenset() add_imports: FrozenSet[str] = frozenset() remove_imports: FrozenSet[str] = frozenset() append_only: bool = False reverse_relative: bool = False force_single_line: bool = False single_line_exclusions: Tuple[str, ...] = () default_section: str = THIRDPARTY import_headings: Dict[str, str] = field(default_factory=dict) import_footers: Dict[str, str] = field(default_factory=dict) balanced_wrapping: bool = False use_parentheses: bool = False order_by_type: bool = True atomic: bool = False lines_before_imports: int = -1 lines_after_imports: int = -1 lines_between_sections: int = 1 lines_between_types: int = 0 combine_as_imports: bool = False combine_star: bool = False include_trailing_comma: bool = False from_first: bool = False verbose: bool = False quiet: bool = False force_adds: bool = False force_alphabetical_sort_within_sections: bool = False force_alphabetical_sort: bool = False force_grid_wrap: int = 0 force_sort_within_sections: bool = False lexicographical: bool = False group_by_package: bool = False ignore_whitespace: bool = False no_lines_before: FrozenSet[str] = frozenset() no_inline_sort: bool = False ignore_comments: bool = False case_sensitive: bool = False sources: Tuple[Dict[str, Any], ...] = () virtual_env: str = "" conda_env: str = "" ensure_newline_before_comments: bool = False directory: str = "" profile: str = "" honor_noqa: bool = False src_paths: Tuple[Path, ...] = () old_finders: bool = False remove_redundant_aliases: bool = False float_to_top: bool = False filter_files: bool = False formatter: str = "" formatting_function: Optional[Callable[[str, str, object], str]] = None color_output: bool = False treat_comments_as_code: FrozenSet[str] = frozenset() treat_all_comments_as_code: bool = False supported_extensions: FrozenSet[str] = SUPPORTED_EXTENSIONS blocked_extensions: FrozenSet[str] = BLOCKED_EXTENSIONS constants: FrozenSet[str] = frozenset() classes: FrozenSet[str] = frozenset() variables: FrozenSet[str] = frozenset() dedup_headings: bool = False only_sections: bool = False only_modified: bool = False combine_straight_imports: bool = False auto_identify_namespace_packages: bool = True namespace_packages: FrozenSet[str] = frozenset() follow_links: bool = True indented_import_headings: bool = True honor_case_in_force_sorted_sections: bool = False sort_relative_in_force_sorted_sections: bool = False overwrite_in_place: bool = False reverse_sort: bool = False star_first: bool = False import_dependencies = Dict[str, str] git_ls_files: Dict[Path, Set[str]] = field(default_factory=dict) format_error: str = "{error}: {message}" format_success: str = "{success}: {message}" sort_order: str = "natural" sort_reexports: bool = False split_on_trailing_comma: bool = False def __post_init__(self) -> None: py_version = self.py_version if py_version == "auto": # pragma: no cover py_version = f"{sys.version_info.major}{sys.version_info.minor}" if py_version not in VALID_PY_TARGETS: raise ValueError( f"The python version {py_version} is not supported. " "You can set a python version with the -py or --python-version flag. " f"The following versions are supported: {VALID_PY_TARGETS}" ) if py_version != "all": object.__setattr__(self, "py_version", f"py{py_version}") if not self.known_standard_library: object.__setattr__( self, "known_standard_library", frozenset(getattr(stdlibs, self.py_version).stdlib) ) if self.multi_line_output == WrapModes.VERTICAL_GRID_GROUPED_NO_COMMA: # type: ignore vertical_grid_grouped = WrapModes.VERTICAL_GRID_GROUPED # type: ignore object.__setattr__(self, "multi_line_output", vertical_grid_grouped) if self.force_alphabetical_sort: object.__setattr__(self, "force_alphabetical_sort_within_sections", True) object.__setattr__(self, "no_sections", True) object.__setattr__(self, "lines_between_types", 1) object.__setattr__(self, "from_first", True) if self.wrap_length > self.line_length: raise ValueError( "wrap_length must be set lower than or equal to line_length: " f"{self.wrap_length} > {self.line_length}." ) def __hash__(self) -> int: return id(self) _DEFAULT_SETTINGS = {**vars(_Config()), "source": "defaults"} class Config(_Config): def __init__( self, settings_file: str = "", settings_path: str = "", config: Optional[_Config] = None, **config_overrides: Any, ): self._known_patterns: Optional[List[Tuple[Pattern[str], str]]] = None self._section_comments: Optional[Tuple[str, ...]] = None self._section_comments_end: Optional[Tuple[str, ...]] = None self._skips: Optional[FrozenSet[str]] = None self._skip_globs: Optional[FrozenSet[str]] = None self._sorting_function: Optional[Callable[..., List[str]]] = None if config: config_vars = vars(config).copy() config_vars.update(config_overrides) config_vars["py_version"] = config_vars["py_version"].replace("py", "") config_vars.pop("_known_patterns") config_vars.pop("_section_comments") config_vars.pop("_section_comments_end") config_vars.pop("_skips") config_vars.pop("_skip_globs") config_vars.pop("_sorting_function") super().__init__(**config_vars) return # We can't use self.quiet to conditionally show warnings before super.__init__() is called # at the end of this method. _Config is also frozen so setting self.quiet isn't possible. # Therefore we extract quiet early here in a variable and use that in warning conditions. quiet = config_overrides.get("quiet", False) sources: List[Dict[str, Any]] = [_DEFAULT_SETTINGS] config_settings: Dict[str, Any] project_root: str if settings_file: config_settings = _get_config_data( settings_file, CONFIG_SECTIONS.get(os.path.basename(settings_file), FALLBACK_CONFIG_SECTIONS), ) project_root = os.path.dirname(settings_file) if not config_settings and not quiet: warn( f"A custom settings file was specified: {settings_file} but no configuration " "was found inside. This can happen when [settings] is used as the config " "header instead of [isort]. " "See: https://pycqa.github.io/isort/docs/configuration/config_files" "#custom-config-files for more information.", stacklevel=2, ) elif settings_path: if not os.path.exists(settings_path): raise InvalidSettingsPath(settings_path) settings_path = os.path.abspath(settings_path) project_root, config_settings = _find_config(settings_path) else: config_settings = {} project_root = os.getcwd() profile_name = config_overrides.get("profile", config_settings.get("profile", "")) profile: Dict[str, Any] = {} if profile_name: if profile_name not in profiles: import pkg_resources for plugin in pkg_resources.iter_entry_points("isort.profiles"): profiles.setdefault(plugin.name, plugin.load()) if profile_name not in profiles: raise ProfileDoesNotExist(profile_name) profile = profiles[profile_name].copy() profile["source"] = f"{profile_name} profile" sources.append(profile) if config_settings: sources.append(config_settings) if config_overrides: config_overrides["source"] = RUNTIME_SOURCE sources.append(config_overrides) combined_config = {**profile, **config_settings, **config_overrides} if "indent" in combined_config: indent = str(combined_config["indent"]) if indent.isdigit(): indent = " " * int(indent) else: indent = indent.strip("'").strip('"') if indent.lower() == "tab": indent = "\t" combined_config["indent"] = indent known_other = {} import_headings = {} import_footers = {} for key, value in tuple(combined_config.items()): # Collect all known sections beyond those that have direct entries if key.startswith(KNOWN_PREFIX) and key not in ( "known_standard_library", "known_future_library", "known_third_party", "known_first_party", "known_local_folder", ): import_heading = key[len(KNOWN_PREFIX) :].lower() maps_to_section = import_heading.upper() combined_config.pop(key) if maps_to_section in KNOWN_SECTION_MAPPING: section_name = f"known_{KNOWN_SECTION_MAPPING[maps_to_section].lower()}" if section_name in combined_config and not quiet: warn( f"Can't set both {key} and {section_name} in the same config file.\n" f"Default to {section_name} if unsure." "\n\n" "See: https://pycqa.github.io/isort/" "#custom-sections-and-ordering.", stacklevel=2, ) else: combined_config[section_name] = frozenset(value) else: known_other[import_heading] = frozenset(value) if maps_to_section not in combined_config.get("sections", ()) and not quiet: warn( f"`{key}` setting is defined, but {maps_to_section} is not" " included in `sections` config option:" f" {combined_config.get('sections', SECTION_DEFAULTS)}.\n\n" "See: https://pycqa.github.io/isort/" "#custom-sections-and-ordering.", stacklevel=2, ) if key.startswith(IMPORT_HEADING_PREFIX): import_headings[key[len(IMPORT_HEADING_PREFIX) :].lower()] = str(value) if key.startswith(IMPORT_FOOTER_PREFIX): import_footers[key[len(IMPORT_FOOTER_PREFIX) :].lower()] = str(value) # Coerce all provided config values into their correct type default_value = _DEFAULT_SETTINGS.get(key, None) if default_value is None: continue combined_config[key] = type(default_value)(value) for section in combined_config.get("sections", ()): if section in SECTION_DEFAULTS: continue if section.lower() not in known_other: config_keys = ", ".join(known_other.keys()) warn( f"`sections` setting includes {section}, but no known_{section.lower()} " "is defined. " f"The following known_SECTION config options are defined: {config_keys}.", stacklevel=2, ) if "directory" not in combined_config: combined_config["directory"] = ( os.path.dirname(config_settings["source"]) if config_settings.get("source", None) else os.getcwd() ) path_root = Path(combined_config.get("directory", project_root)).resolve() path_root = path_root if path_root.is_dir() else path_root.parent if "src_paths" not in combined_config: combined_config["src_paths"] = (path_root / "src", path_root) else: src_paths: List[Path] = [] for src_path in combined_config.get("src_paths", ()): full_paths = ( path_root.glob(src_path) if "*" in str(src_path) else [path_root / src_path] ) for path in full_paths: if path not in src_paths: src_paths.append(path) combined_config["src_paths"] = tuple(src_paths) if "formatter" in combined_config: import pkg_resources for plugin in pkg_resources.iter_entry_points("isort.formatters"): if plugin.name == combined_config["formatter"]: combined_config["formatting_function"] = plugin.load() break else: raise FormattingPluginDoesNotExist(combined_config["formatter"]) # Remove any config values that are used for creating config object but # aren't defined in dataclass combined_config.pop("source", None) combined_config.pop("sources", None) combined_config.pop("runtime_src_paths", None) deprecated_options_used = [ option for option in combined_config if option in DEPRECATED_SETTINGS ] if deprecated_options_used: for deprecated_option in deprecated_options_used: combined_config.pop(deprecated_option) if not quiet: warn( "W0503: Deprecated config options were used: " f"{', '.join(deprecated_options_used)}." "Please see the 5.0.0 upgrade guide: " "https://pycqa.github.io/isort/docs/upgrade_guides/5.0.0.html", stacklevel=2, ) if known_other: combined_config["known_other"] = known_other if import_headings: for import_heading_key in import_headings: combined_config.pop(f"{IMPORT_HEADING_PREFIX}{import_heading_key}") combined_config["import_headings"] = import_headings if import_footers: for import_footer_key in import_footers: combined_config.pop(f"{IMPORT_FOOTER_PREFIX}{import_footer_key}") combined_config["import_footers"] = import_footers unsupported_config_errors = {} for option in set(combined_config.keys()).difference( getattr(_Config, "__dataclass_fields__", {}).keys() ): for source in reversed(sources): if option in source: unsupported_config_errors[option] = { "value": source[option], "source": source["source"], } if unsupported_config_errors: raise UnsupportedSettings(unsupported_config_errors) super().__init__(sources=tuple(sources), **combined_config) def is_supported_filetype(self, file_name: str) -> bool: _root, ext = os.path.splitext(file_name) ext = ext.lstrip(".") if ext in self.supported_extensions: return True if ext in self.blocked_extensions: return False # Skip editor backup files. if file_name.endswith("~"): return False try: if stat.S_ISFIFO(os.stat(file_name).st_mode): return False except OSError: pass try: with open(file_name, "rb") as fp: line = fp.readline(100) except OSError: return False return bool(_SHEBANG_RE.match(line)) def _check_folder_git_ls_files(self, folder: str) -> Optional[Path]: env = {**os.environ, "LANG": "C.UTF-8"} try: topfolder_result = subprocess.check_output( # nosec # skipcq: PYL-W1510 ["git", "-C", folder, "rev-parse", "--show-toplevel"], encoding="utf-8", env=env ) except subprocess.CalledProcessError: return None git_folder = Path(topfolder_result.rstrip()).resolve() # files committed to git tracked_files = ( subprocess.check_output( # nosec # skipcq: PYL-W1510 ["git", "-C", str(git_folder), "ls-files", "-z"], encoding="utf-8", env=env, ) .rstrip("\0") .split("\0") ) # files that haven't been committed yet, but aren't ignored tracked_files_others = ( subprocess.check_output( # nosec # skipcq: PYL-W1510 ["git", "-C", str(git_folder), "ls-files", "-z", "--others", "--exclude-standard"], encoding="utf-8", env=env, ) .rstrip("\0") .split("\0") ) self.git_ls_files[git_folder] = { str(git_folder / Path(f)) for f in tracked_files + tracked_files_others } return git_folder def is_skipped(self, file_path: Path) -> bool: """Returns True if the file and/or folder should be skipped based on current settings.""" if self.directory and Path(self.directory) in file_path.resolve().parents: file_name = os.path.relpath(file_path.resolve(), self.directory) else: file_name = str(file_path) os_path = str(file_path) normalized_path = os_path.replace("\\", "/") if normalized_path[1:2] == ":": normalized_path = normalized_path[2:] for skip_path in self.skips: if posixpath.abspath(normalized_path) == posixpath.abspath( skip_path.replace("\\", "/") ): return True position = os.path.split(file_name) while position[1]: if position[1] in self.skips: return True position = os.path.split(position[0]) for sglob in self.skip_globs: if fnmatch.fnmatch(file_name, sglob) or fnmatch.fnmatch("/" + file_name, sglob): return True if not (os.path.isfile(os_path) or os.path.isdir(os_path) or os.path.islink(os_path)): return True if self.skip_gitignore: if file_path.name == ".git": # pragma: no cover return True git_folder = None file_paths = [file_path, file_path.resolve()] for folder in self.git_ls_files: if any(folder in path.parents for path in file_paths): git_folder = folder break else: git_folder = self._check_folder_git_ls_files(str(file_path.parent)) # git_ls_files are good files you should parse. If you're not in the allow list, skip. if ( git_folder and not file_path.is_dir() and str(file_path.resolve()) not in self.git_ls_files[git_folder] ): return True return False @property def known_patterns(self) -> List[Tuple[Pattern[str], str]]: if self._known_patterns is not None: return self._known_patterns self._known_patterns = [] pattern_sections = [STDLIB] + [section for section in self.sections if section != STDLIB] for placement in reversed(pattern_sections): known_placement = KNOWN_SECTION_MAPPING.get(placement, placement).lower() config_key = f"{KNOWN_PREFIX}{known_placement}" known_modules = getattr(self, config_key, self.known_other.get(known_placement, ())) extra_modules = getattr(self, f"extra_{known_placement}", ()) all_modules = set(extra_modules).union(known_modules) known_patterns = [ pattern for known_pattern in all_modules for pattern in self._parse_known_pattern(known_pattern) ] for known_pattern in known_patterns: regexp = "^" + known_pattern.replace("*", ".*").replace("?", ".?") + "$" self._known_patterns.append((re.compile(regexp), placement)) return self._known_patterns @property def section_comments(self) -> Tuple[str, ...]: if self._section_comments is not None: return self._section_comments self._section_comments = tuple(f"# {heading}" for heading in self.import_headings.values()) return self._section_comments @property def section_comments_end(self) -> Tuple[str, ...]: if self._section_comments_end is not None: return self._section_comments_end self._section_comments_end = tuple(f"# {footer}" for footer in self.import_footers.values()) return self._section_comments_end @property def skips(self) -> FrozenSet[str]: if self._skips is not None: return self._skips self._skips = self.skip.union(self.extend_skip) return self._skips @property def skip_globs(self) -> FrozenSet[str]: if self._skip_globs is not None: return self._skip_globs self._skip_globs = self.skip_glob.union(self.extend_skip_glob) return self._skip_globs @property def sorting_function(self) -> Callable[..., List[str]]: if self._sorting_function is not None: return self._sorting_function if self.sort_order == "natural": self._sorting_function = sorting.naturally elif self.sort_order == "native": self._sorting_function = sorted else: available_sort_orders = ["natural", "native"] import pkg_resources for sort_plugin in pkg_resources.iter_entry_points("isort.sort_function"): available_sort_orders.append(sort_plugin.name) if sort_plugin.name == self.sort_order: self._sorting_function = sort_plugin.load() break else: raise SortingFunctionDoesNotExist(self.sort_order, available_sort_orders) return self._sorting_function def _parse_known_pattern(self, pattern: str) -> List[str]: """Expand pattern if identified as a directory and return found sub packages""" if pattern.endswith(os.path.sep): patterns = [ filename for filename in os.listdir(os.path.join(self.directory, pattern)) if os.path.isdir(os.path.join(self.directory, pattern, filename)) ] else: patterns = [pattern] return patterns def _get_str_to_type_converter(setting_name: str) -> Union[Callable[[str], Any], Type[Any]]: type_converter: Union[Callable[[str], Any], Type[Any]] = type( _DEFAULT_SETTINGS.get(setting_name, "") ) if type_converter == WrapModes: type_converter = wrap_mode_from_string return type_converter def _as_list(value: str) -> List[str]: if isinstance(value, list): return [item.strip() for item in value] filtered = [item.strip() for item in value.replace("\n", ",").split(",") if item.strip()] return filtered def _abspaths(cwd: str, values: Iterable[str]) -> Set[str]: paths = { ( os.path.join(cwd, value) if not value.startswith(os.path.sep) and value.endswith(os.path.sep) else value ) for value in values } return paths def _find_config(path: str) -> Tuple[str, Dict[str, Any]]: current_directory = path tries = 0 while current_directory and tries < MAX_CONFIG_SEARCH_DEPTH: for config_file_name in CONFIG_SOURCES: potential_config_file = os.path.join(current_directory, config_file_name) if os.path.isfile(potential_config_file): config_data: Dict[str, Any] try: config_data = _get_config_data( potential_config_file, CONFIG_SECTIONS[config_file_name] ) except Exception: warn( f"Failed to pull configuration information from {potential_config_file}", stacklevel=2, ) config_data = {} if config_data: return (current_directory, config_data) for stop_dir in STOP_CONFIG_SEARCH_ON_DIRS: if os.path.isdir(os.path.join(current_directory, stop_dir)): return (current_directory, {}) new_directory = os.path.split(current_directory)[0] if new_directory == current_directory: break current_directory = new_directory tries += 1 return (path, {}) def find_all_configs(path: str) -> Trie: """ Looks for config files in the path provided and in all of its sub-directories. Parses and stores any config file encountered in a trie and returns the root of the trie """ trie_root = Trie("default", {}) for dirpath, _, _ in os.walk(path): for config_file_name in CONFIG_SOURCES: potential_config_file = os.path.join(dirpath, config_file_name) if os.path.isfile(potential_config_file): config_data: Dict[str, Any] try: config_data = _get_config_data( potential_config_file, CONFIG_SECTIONS[config_file_name] ) except Exception: warn( f"Failed to pull configuration information from {potential_config_file}", stacklevel=2, ) config_data = {} if config_data: trie_root.insert(potential_config_file, config_data) break return trie_root def _get_config_data(file_path: str, sections: Tuple[str, ...]) -> Dict[str, Any]: settings: Dict[str, Any] = {} if file_path.endswith(".toml"): with open(file_path, "rb") as bin_config_file: config = tomllib.load(bin_config_file) for section in sections: config_section = config for key in section.split("."): config_section = config_section.get(key, {}) settings.update(config_section) else: with open(file_path, encoding="utf-8") as config_file: if file_path.endswith(".editorconfig"): line = "\n" last_position = config_file.tell() while line: line = config_file.readline() if "[" in line: config_file.seek(last_position) break last_position = config_file.tell() config = configparser.ConfigParser(strict=False) config.read_file(config_file) for section in sections: if section.startswith("*.{") and section.endswith("}"): extension = section[len("*.{") : -1] for config_key in config: if ( config_key.startswith("*.{") and config_key.endswith("}") and extension in (text.strip() for text in config_key[len("*.{") : -1].split(",")) ): settings.update(config.items(config_key)) elif config.has_section(section): settings.update(config.items(section)) if settings: settings["source"] = file_path if file_path.endswith(".editorconfig"): indent_style = settings.pop("indent_style", "").strip() indent_size = settings.pop("indent_size", "").strip() if indent_size == "tab": indent_size = settings.pop("tab_width", "").strip() if indent_style == "space": settings["indent"] = " " * ((indent_size and int(indent_size)) or 4) elif indent_style == "tab": settings["indent"] = "\t" * ((indent_size and int(indent_size)) or 1) max_line_length = settings.pop("max_line_length", "").strip() if max_line_length and (max_line_length == "off" or max_line_length.isdigit()): settings["line_length"] = ( float("inf") if max_line_length == "off" else int(max_line_length) ) settings = { key: value for key, value in settings.items() if key in _DEFAULT_SETTINGS or key.startswith(KNOWN_PREFIX) } for key, value in settings.items(): existing_value_type = _get_str_to_type_converter(key) if existing_value_type is tuple: settings[key] = tuple(_as_list(value)) elif existing_value_type is frozenset: settings[key] = frozenset(_as_list(settings.get(key))) # type: ignore elif existing_value_type is bool: # Only some configuration formats support native boolean values. if not isinstance(value, bool): value = _as_bool(value) settings[key] = value elif key.startswith(KNOWN_PREFIX): settings[key] = _abspaths(os.path.dirname(file_path), _as_list(value)) elif key == "force_grid_wrap": try: result = existing_value_type(value) except ValueError: # backwards compatibility for true / false force grid wrap result = 0 if value.lower().strip() == "false" else 2 settings[key] = result elif key == "comment_prefix": settings[key] = str(value).strip("'").strip('"') else: settings[key] = existing_value_type(value) return settings def _as_bool(value: str) -> bool: """Given a string value that represents True or False, returns the Boolean equivalent. Heavily inspired from distutils strtobool. """ try: return _STR_BOOLEAN_MAPPING[value.lower()] except KeyError: raise ValueError(f"invalid truth value {value}") DEFAULT_CONFIG = Config() isort-6.0.1/isort/setuptools_commands.py0000644000000000000000000000446413615410400015422 0ustar00import glob import os import sys from typing import Any, Iterator from warnings import warn import setuptools from . import api from .settings import DEFAULT_CONFIG class ISortCommand(setuptools.Command): """The :class:`ISortCommand` class is used by setuptools to perform imports checks on registered modules. """ description = "Run isort on modules registered in setuptools" # Potentially unused variable - check if can be safely removed user_options: list[Any] = [] # type: ignore[misc] def initialize_options(self) -> None: default_settings = vars(DEFAULT_CONFIG).copy() for key, value in default_settings.items(): setattr(self, key, value) def finalize_options(self) -> None: """Get options from config files.""" self.arguments: dict[str, Any] = {} # skipcq: PYL-W0201 self.arguments["settings_path"] = os.getcwd() def distribution_files(self) -> Iterator[str]: """Find distribution packages.""" # This is verbatim from flake8 if self.distribution.packages: # pragma: no cover package_dirs = self.distribution.package_dir or {} for package in self.distribution.packages: pkg_dir = package if package in package_dirs: pkg_dir = package_dirs[package] elif "" in package_dirs: # pragma: no cover pkg_dir = package_dirs[""] + os.path.sep + pkg_dir yield pkg_dir.replace(".", os.path.sep) if self.distribution.py_modules: for filename in self.distribution.py_modules: yield f"{filename}.py" # Don't miss the setup.py file itself yield "setup.py" def run(self) -> None: arguments = self.arguments wrong_sorted_files = False for path in self.distribution_files(): for python_file in glob.iglob(os.path.join(path, "*.py")): try: if not api.check_file(python_file, **arguments): wrong_sorted_files = True # pragma: no cover except OSError as error: # pragma: no cover warn(f"Unable to parse file {python_file} due to {error}", stacklevel=2) if wrong_sorted_files: sys.exit(1) # pragma: no cover isort-6.0.1/isort/sorting.py0000644000000000000000000001062013615410400012774 0ustar00import re from typing import TYPE_CHECKING, Any, Callable, Iterable, List, Optional if TYPE_CHECKING: from .settings import Config else: Config = Any _import_line_intro_re = re.compile("^(?:from|import) ") _import_line_midline_import_re = re.compile(" import ") def module_key( module_name: str, config: Config, sub_imports: bool = False, ignore_case: bool = False, section_name: Optional[Any] = None, straight_import: Optional[bool] = False, ) -> str: match = re.match(r"^(\.+)\s*(.*)", module_name) if match: sep = " " if config.reverse_relative else "_" module_name = sep.join(match.groups()) prefix = "" if ignore_case: module_name = str(module_name).lower() else: module_name = str(module_name) if sub_imports and config.order_by_type: if module_name in config.constants: prefix = "A" elif module_name in config.classes: prefix = "B" elif module_name in config.variables: prefix = "C" elif module_name.isupper() and len(module_name) > 1: # see issue #376 prefix = "A" elif module_name in config.classes or module_name[0:1].isupper(): prefix = "B" else: prefix = "C" if not config.case_sensitive: module_name = module_name.lower() length_sort = ( config.length_sort or (config.length_sort_straight and straight_import) or str(section_name).lower() in config.length_sort_sections ) _length_sort_maybe = (str(len(module_name)) + ":" + module_name) if length_sort else module_name return f"{(module_name in config.force_to_top and 'A') or 'B'}{prefix}{_length_sort_maybe}" def section_key(line: str, config: Config) -> str: section = "B" if ( not config.sort_relative_in_force_sorted_sections and config.reverse_relative and line.startswith("from .") ): match = re.match(r"^from (\.+)\s*(.*)", line) if match: # pragma: no cover - regex always matches if line starts with "from ." line = f"from {' '.join(match.groups())}" if config.group_by_package and line.strip().startswith("from"): line = line.split(" import ", 1)[0] if config.lexicographical: line = _import_line_intro_re.sub("", _import_line_midline_import_re.sub(".", line)) else: line = re.sub("^from ", "", line) line = re.sub("^import ", "", line) if config.sort_relative_in_force_sorted_sections: sep = " " if config.reverse_relative else "_" line = re.sub(r"^(\.+)", rf"\1{sep}", line) if line.split(" ")[0] in config.force_to_top: section = "A" # * If honor_case_in_force_sorted_sections is true, and case_sensitive and # order_by_type are different, only ignore case in part of the line. # * Otherwise, let order_by_type decide the sorting of the whole line. This # is only "correct" if case_sensitive and order_by_type have the same value. if config.honor_case_in_force_sorted_sections and config.case_sensitive != config.order_by_type: split_module = line.split(" import ", 1) if len(split_module) > 1: module_name, names = split_module if not config.case_sensitive: module_name = module_name.lower() if not config.order_by_type: names = names.lower() line = f"{module_name} import {names}" elif not config.case_sensitive: line = line.lower() elif not config.order_by_type: line = line.lower() return f"{section}{len(line) if config.length_sort else ''}{line}" def sort( config: Config, to_sort: Iterable[str], key: Optional[Callable[[str], Any]] = None, reverse: bool = False, ) -> List[str]: return config.sorting_function(to_sort, key=key, reverse=reverse) def naturally( to_sort: Iterable[str], key: Optional[Callable[[str], Any]] = None, reverse: bool = False ) -> List[str]: """Returns a naturally sorted list""" if key is None: key_callback = _natural_keys else: def key_callback(text: str) -> List[Any]: return _natural_keys(key(text)) return sorted(to_sort, key=key_callback, reverse=reverse) def _atoi(text: str) -> Any: return int(text) if text.isdigit() else text def _natural_keys(text: str) -> List[Any]: return [_atoi(c) for c in re.split(r"(\d+)", text)] isort-6.0.1/isort/utils.py0000644000000000000000000000464613615410400012462 0ustar00import os import sys from functools import lru_cache from pathlib import Path from typing import Any, Dict, Optional, Tuple class TrieNode: def __init__(self, config_file: str = "", config_data: Optional[Dict[str, Any]] = None) -> None: if not config_data: config_data = {} self.nodes: Dict[str, TrieNode] = {} self.config_info: Tuple[str, Dict[str, Any]] = (config_file, config_data) class Trie: """ A prefix tree to store the paths of all config files and to search the nearest config associated with each file """ def __init__(self, config_file: str = "", config_data: Optional[Dict[str, Any]] = None) -> None: self.root: TrieNode = TrieNode(config_file, config_data) def insert(self, config_file: str, config_data: Dict[str, Any]) -> None: resolved_config_path_as_tuple = Path(config_file).parent.resolve().parts temp = self.root for path in resolved_config_path_as_tuple: if path not in temp.nodes: temp.nodes[path] = TrieNode() temp = temp.nodes[path] temp.config_info = (config_file, config_data) def search(self, filename: str) -> Tuple[str, Dict[str, Any]]: """ Returns the closest config relative to filename by doing a depth first search on the prefix tree. """ resolved_file_path_as_tuple = Path(filename).resolve().parts temp = self.root last_stored_config: Tuple[str, Dict[str, Any]] = ("", {}) for path in resolved_file_path_as_tuple: if temp.config_info[0]: last_stored_config = temp.config_info if path not in temp.nodes: break temp = temp.nodes[path] return last_stored_config @lru_cache(maxsize=1000) def exists_case_sensitive(path: str) -> bool: """Returns if the given path exists and also matches the case on Windows. When finding files that can be imported, it is important for the cases to match because while file os.path.exists("module.py") and os.path.exists("MODULE.py") both return True on Windows, Python can only import using the case of the real file. """ result = os.path.exists(path) if result and (sys.platform.startswith("win") or sys.platform == "darwin"): # pragma: no cover directory, basename = os.path.split(path) result = basename in os.listdir(directory) return result isort-6.0.1/isort/wrap.py0000644000000000000000000001436713615410400012274 0ustar00import copy import re from typing import List, Optional, Sequence from .settings import DEFAULT_CONFIG, Config from .wrap_modes import WrapModes as Modes from .wrap_modes import formatter_from_string, vertical_hanging_indent def import_statement( import_start: str, from_imports: List[str], comments: Sequence[str] = (), line_separator: str = "\n", config: Config = DEFAULT_CONFIG, multi_line_output: Optional[Modes] = None, explode: bool = False, ) -> str: """Returns a multi-line wrapped form of the provided from import statement.""" if explode: formatter = vertical_hanging_indent line_length = 1 include_trailing_comma = True else: formatter = formatter_from_string((multi_line_output or config.multi_line_output).name) line_length = config.wrap_length or config.line_length include_trailing_comma = config.include_trailing_comma dynamic_indent = " " * (len(import_start) + 1) indent = config.indent statement = formatter( statement=import_start, imports=copy.copy(from_imports), white_space=dynamic_indent, indent=indent, line_length=line_length, comments=comments, line_separator=line_separator, comment_prefix=config.comment_prefix, include_trailing_comma=include_trailing_comma, remove_comments=config.ignore_comments, ) if config.balanced_wrapping: lines = statement.split(line_separator) line_count = len(lines) if len(lines) > 1: minimum_length = min(len(line) for line in lines[:-1]) else: minimum_length = 0 new_import_statement = statement while len(lines[-1]) < minimum_length and len(lines) == line_count and line_length > 10: statement = new_import_statement line_length -= 1 new_import_statement = formatter( statement=import_start, imports=copy.copy(from_imports), white_space=dynamic_indent, indent=indent, line_length=line_length, comments=comments, line_separator=line_separator, comment_prefix=config.comment_prefix, include_trailing_comma=include_trailing_comma, remove_comments=config.ignore_comments, ) lines = new_import_statement.split(line_separator) if statement.count(line_separator) == 0: return _wrap_line(statement, line_separator, config) return statement def line(content: str, line_separator: str, config: Config = DEFAULT_CONFIG) -> str: """Returns a line wrapped to the specified line-length, if possible.""" wrap_mode = config.multi_line_output if len(content) > config.line_length and wrap_mode != Modes.NOQA: # type: ignore line_without_comment = content comment = None if "#" in content: line_without_comment, comment = content.split("#", 1) for splitter in ("import ", "cimport ", ".", "as "): exp = r"\b" + re.escape(splitter) + r"\b" if re.search(exp, line_without_comment) and not line_without_comment.strip().startswith( splitter ): line_parts = re.split(exp, line_without_comment) if comment and not (config.use_parentheses and "noqa" in comment): _comma_maybe = ( "," if ( config.include_trailing_comma and config.use_parentheses and not line_without_comment.rstrip().endswith(",") ) else "" ) line_parts[-1] = ( f"{line_parts[-1].strip()}{_comma_maybe}{config.comment_prefix}{comment}" ) next_line = [] while (len(content) + 2) > ( config.wrap_length or config.line_length ) and line_parts: next_line.append(line_parts.pop()) content = splitter.join(line_parts) if not content: content = next_line.pop() cont_line = _wrap_line( config.indent + splitter.join(next_line).lstrip(), line_separator, config, ) if config.use_parentheses: if splitter == "as ": output = f"{content}{splitter}{cont_line.lstrip()}" else: _comma = "," if config.include_trailing_comma and not comment else "" if wrap_mode in ( Modes.VERTICAL_HANGING_INDENT, # type: ignore Modes.VERTICAL_GRID_GROUPED, # type: ignore ): _separator = line_separator else: _separator = "" noqa_comment = "" if comment and "noqa" in comment: noqa_comment = f"{config.comment_prefix}{comment}" cont_line = cont_line.rstrip() _comma = "," if config.include_trailing_comma else "" output = ( f"{content}{splitter}({noqa_comment}" f"{line_separator}{cont_line}{_comma}{_separator})" ) lines = output.split(line_separator) if config.comment_prefix in lines[-1] and lines[-1].endswith(")"): content, comment = lines[-1].split(config.comment_prefix, 1) lines[-1] = content + ")" + config.comment_prefix + comment[:-1] output = line_separator.join(lines) return output return f"{content}{splitter}\\{line_separator}{cont_line}" elif len(content) > config.line_length and wrap_mode == Modes.NOQA and "# NOQA" not in content: # type: ignore return f"{content}{config.comment_prefix} NOQA" return content _wrap_line = line isort-6.0.1/isort/wrap_modes.py0000644000000000000000000003220713615410400013454 0ustar00"""Defines all wrap modes that can be used when outputting formatted imports""" import enum from inspect import signature from typing import Any, Callable, Dict, List import isort.comments _wrap_modes: Dict[str, Callable[..., str]] = {} def from_string(value: str) -> "WrapModes": return getattr(WrapModes, str(value), None) or WrapModes(int(value)) def formatter_from_string(name: str) -> Callable[..., str]: return _wrap_modes.get(name.upper(), grid) def _wrap_mode_interface( statement: str, imports: List[str], white_space: str, indent: str, line_length: int, comments: List[str], line_separator: str, comment_prefix: str, include_trailing_comma: bool, remove_comments: bool, ) -> str: """Defines the common interface used by all wrap mode functions""" return "" def _wrap_mode(function: Callable[..., str]) -> Callable[..., str]: """Registers an individual wrap mode. Function name and order are significant and used for creating enum. """ _wrap_modes[function.__name__.upper()] = function function.__signature__ = signature(_wrap_mode_interface) # type: ignore function.__annotations__ = _wrap_mode_interface.__annotations__ return function @_wrap_mode def grid(**interface: Any) -> str: if not interface["imports"]: return "" interface["statement"] += "(" + interface["imports"].pop(0) while interface["imports"]: next_import = interface["imports"].pop(0) next_statement = isort.comments.add_to_line( interface["comments"], interface["statement"] + ", " + next_import, removed=interface["remove_comments"], comment_prefix=interface["comment_prefix"], ) if ( len(next_statement.split(interface["line_separator"])[-1]) + 1 > interface["line_length"] ): lines = [f"{interface['white_space']}{next_import.split(' ')[0]}"] for part in next_import.split(" ")[1:]: new_line = f"{lines[-1]} {part}" if len(new_line) + 1 > interface["line_length"]: lines.append(f"{interface['white_space']}{part}") else: lines[-1] = new_line next_import = interface["line_separator"].join(lines) interface["statement"] = ( isort.comments.add_to_line( interface["comments"], f"{interface['statement']},", removed=interface["remove_comments"], comment_prefix=interface["comment_prefix"], ) + f"{interface['line_separator']}{next_import}" ) interface["comments"] = [] else: interface["statement"] += ", " + next_import return f"{interface['statement']}{',' if interface['include_trailing_comma'] else ''})" @_wrap_mode def vertical(**interface: Any) -> str: if not interface["imports"]: return "" first_import = ( isort.comments.add_to_line( interface["comments"], interface["imports"].pop(0) + ",", removed=interface["remove_comments"], comment_prefix=interface["comment_prefix"], ) + interface["line_separator"] + interface["white_space"] ) _imports = ("," + interface["line_separator"] + interface["white_space"]).join( interface["imports"] ) _comma_maybe = "," if interface["include_trailing_comma"] else "" return f"{interface['statement']}({first_import}{_imports}{_comma_maybe})" def _hanging_indent_end_line(line: str) -> str: if not line.endswith(" "): line += " " return line + "\\" @_wrap_mode def hanging_indent(**interface: Any) -> str: if not interface["imports"]: return "" line_length_limit = interface["line_length"] - 3 next_import = interface["imports"].pop(0) next_statement = interface["statement"] + next_import # Check for first import if len(next_statement) > line_length_limit: next_statement = ( _hanging_indent_end_line(interface["statement"]) + interface["line_separator"] + interface["indent"] + next_import ) interface["statement"] = next_statement while interface["imports"]: next_import = interface["imports"].pop(0) next_statement = interface["statement"] + ", " + next_import if len(next_statement.split(interface["line_separator"])[-1]) > line_length_limit: next_statement = ( _hanging_indent_end_line(interface["statement"] + ",") + f"{interface['line_separator']}{interface['indent']}{next_import}" ) interface["statement"] = next_statement if interface["comments"]: statement_with_comments = isort.comments.add_to_line( interface["comments"], interface["statement"], removed=interface["remove_comments"], comment_prefix=interface["comment_prefix"], ) if len(statement_with_comments.split(interface["line_separator"])[-1]) <= ( line_length_limit + 2 ): return statement_with_comments return ( _hanging_indent_end_line(interface["statement"]) + str(interface["line_separator"]) + isort.comments.add_to_line( interface["comments"], interface["indent"], removed=interface["remove_comments"], comment_prefix=interface["comment_prefix"].lstrip(), ) ) return str(interface["statement"]) @_wrap_mode def vertical_hanging_indent(**interface: Any) -> str: _line_with_comments = isort.comments.add_to_line( interface["comments"], "", removed=interface["remove_comments"], comment_prefix=interface["comment_prefix"], ) _imports = ("," + interface["line_separator"] + interface["indent"]).join(interface["imports"]) _comma_maybe = "," if interface["include_trailing_comma"] else "" return ( f"{interface['statement']}({_line_with_comments}{interface['line_separator']}" f"{interface['indent']}{_imports}{_comma_maybe}{interface['line_separator']})" ) def _vertical_grid_common(need_trailing_char: bool, **interface: Any) -> str: if not interface["imports"]: return "" interface["statement"] += ( isort.comments.add_to_line( interface["comments"], "(", removed=interface["remove_comments"], comment_prefix=interface["comment_prefix"], ) + interface["line_separator"] + interface["indent"] + interface["imports"].pop(0) ) while interface["imports"]: next_import = interface["imports"].pop(0) next_statement = f"{interface['statement']}, {next_import}" current_line_length = len(next_statement.split(interface["line_separator"])[-1]) if interface["imports"] or interface["include_trailing_comma"]: # We need to account for a comma after this import. current_line_length += 1 if not interface["imports"] and need_trailing_char: # We need to account for a closing ) we're going to add. current_line_length += 1 if current_line_length > interface["line_length"]: next_statement = ( f"{interface['statement']},{interface['line_separator']}" f"{interface['indent']}{next_import}" ) interface["statement"] = next_statement if interface["include_trailing_comma"]: interface["statement"] += "," return str(interface["statement"]) @_wrap_mode def vertical_grid(**interface: Any) -> str: return _vertical_grid_common(need_trailing_char=True, **interface) + ")" @_wrap_mode def vertical_grid_grouped(**interface: Any) -> str: return ( _vertical_grid_common(need_trailing_char=False, **interface) + str(interface["line_separator"]) + ")" ) @_wrap_mode def vertical_grid_grouped_no_comma(**interface: Any) -> str: # This is a deprecated alias for vertical_grid_grouped above. This function # needs to exist for backwards compatibility but should never get called. raise NotImplementedError @_wrap_mode def noqa(**interface: Any) -> str: _imports = ", ".join(interface["imports"]) retval = f"{interface['statement']}{_imports}" comment_str = " ".join(interface["comments"]) if interface["comments"]: if ( len(retval) + len(interface["comment_prefix"]) + 1 + len(comment_str) <= interface["line_length"] ): return f"{retval}{interface['comment_prefix']} {comment_str}" if "NOQA" in interface["comments"]: return f"{retval}{interface['comment_prefix']} {comment_str}" return f"{retval}{interface['comment_prefix']} NOQA {comment_str}" if len(retval) <= interface["line_length"]: return retval return f"{retval}{interface['comment_prefix']} NOQA" @_wrap_mode def vertical_hanging_indent_bracket(**interface: Any) -> str: if not interface["imports"]: return "" statement = vertical_hanging_indent(**interface) return f'{statement[:-1]}{interface["indent"]})' @_wrap_mode def vertical_prefix_from_module_import(**interface: Any) -> str: if not interface["imports"]: return "" prefix_statement = interface["statement"] output_statement = prefix_statement + interface["imports"].pop(0) comments = interface["comments"] statement = output_statement statement_with_comments = "" for next_import in interface["imports"]: statement = statement + ", " + next_import statement_with_comments = isort.comments.add_to_line( comments, statement, removed=interface["remove_comments"], comment_prefix=interface["comment_prefix"], ) if ( len(statement_with_comments.split(interface["line_separator"])[-1]) + 1 > interface["line_length"] ): statement = ( isort.comments.add_to_line( comments, output_statement, removed=interface["remove_comments"], comment_prefix=interface["comment_prefix"], ) + f"{interface['line_separator']}{prefix_statement}{next_import}" ) comments = [] output_statement = statement if comments and statement_with_comments: output_statement = statement_with_comments return str(output_statement) @_wrap_mode def hanging_indent_with_parentheses(**interface: Any) -> str: if not interface["imports"]: return "" line_length_limit = interface["line_length"] - 1 interface["statement"] += "(" next_import = interface["imports"].pop(0) next_statement = interface["statement"] + next_import # Check for first import if len(next_statement) > line_length_limit: next_statement = ( isort.comments.add_to_line( interface["comments"], interface["statement"], removed=interface["remove_comments"], comment_prefix=interface["comment_prefix"], ) + f"{interface['line_separator']}{interface['indent']}{next_import}" ) interface["comments"] = [] interface["statement"] = next_statement while interface["imports"]: next_import = interface["imports"].pop(0) if ( interface["line_separator"] not in interface["statement"] and "#" in interface["statement"] ): # pragma: no cover # TODO: fix, this is because of test run inconsistency. line, comments = interface["statement"].split("#", 1) next_statement = ( f"{line.rstrip()}, {next_import}{interface['comment_prefix']}{comments}" ) else: next_statement = isort.comments.add_to_line( interface["comments"], interface["statement"] + ", " + next_import, removed=interface["remove_comments"], comment_prefix=interface["comment_prefix"], ) current_line = next_statement.split(interface["line_separator"])[-1] if len(current_line) > line_length_limit: next_statement = ( isort.comments.add_to_line( interface["comments"], interface["statement"] + ",", removed=interface["remove_comments"], comment_prefix=interface["comment_prefix"], ) + f"{interface['line_separator']}{interface['indent']}{next_import}" ) interface["comments"] = [] interface["statement"] = next_statement return f"{interface['statement']}{',' if interface['include_trailing_comma'] else ''})" @_wrap_mode def backslash_grid(**interface: Any) -> str: interface["indent"] = interface["white_space"][:-1] return hanging_indent(**interface) WrapModes = enum.Enum( # type: ignore "WrapModes", {wrap_mode: index for index, wrap_mode in enumerate(_wrap_modes.keys())} ) isort-6.0.1/isort/_vendored/tomli/LICENSE0000644000000000000000000000206013615410400015032 0ustar00MIT License Copyright (c) 2021 Taneli Hukkinen Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. isort-6.0.1/isort/_vendored/tomli/__init__.py0000644000000000000000000000032513615410400016140 0ustar00"""A lil' TOML parser.""" __all__ = ("loads", "load", "TOMLDecodeError") __version__ = "1.2.0" # DO NOT EDIT THIS LINE MANUALLY. LET bump2version UTILITY DO IT from ._parser import TOMLDecodeError, load, loads isort-6.0.1/isort/_vendored/tomli/_parser.py0000644000000000000000000005162513615410400016045 0ustar00import string import warnings from types import MappingProxyType from typing import IO, Any, Callable, Dict, FrozenSet, Iterable, NamedTuple, Optional, Tuple from ._re import ( RE_DATETIME, RE_LOCALTIME, RE_NUMBER, match_to_datetime, match_to_localtime, match_to_number, ) ASCII_CTRL = frozenset(chr(i) for i in range(32)) | frozenset(chr(127)) # Neither of these sets include quotation mark or backslash. They are # currently handled as separate cases in the parser functions. ILLEGAL_BASIC_STR_CHARS = ASCII_CTRL - frozenset("\t") ILLEGAL_MULTILINE_BASIC_STR_CHARS = ASCII_CTRL - frozenset("\t\n\r") ILLEGAL_LITERAL_STR_CHARS = ILLEGAL_BASIC_STR_CHARS ILLEGAL_MULTILINE_LITERAL_STR_CHARS = ASCII_CTRL - frozenset("\t\n") ILLEGAL_COMMENT_CHARS = ILLEGAL_BASIC_STR_CHARS TOML_WS = frozenset(" \t") TOML_WS_AND_NEWLINE = TOML_WS | frozenset("\n") BARE_KEY_CHARS = frozenset(string.ascii_letters + string.digits + "-_") KEY_INITIAL_CHARS = BARE_KEY_CHARS | frozenset("\"'") HEXDIGIT_CHARS = frozenset(string.hexdigits) BASIC_STR_ESCAPE_REPLACEMENTS = MappingProxyType( { "\\b": "\u0008", # backspace "\\t": "\u0009", # tab "\\n": "\u000A", # linefeed "\\f": "\u000C", # form feed "\\r": "\u000D", # carriage return '\\"': "\u0022", # quote "\\\\": "\u005C", # backslash } ) # Type annotations ParseFloat = Callable[[str], Any] Key = Tuple[str, ...] Pos = int class TOMLDecodeError(ValueError): """An error raised if a document is not valid TOML.""" def load(fp: IO, *, parse_float: ParseFloat = float) -> Dict[str, Any]: """Parse TOML from a file object.""" s = fp.read() if isinstance(s, bytes): s = s.decode() else: warnings.warn( "Text file object support is deprecated in favor of binary file objects." ' Use `open("foo.toml", "rb")` to open the file in binary mode.', DeprecationWarning, ) return loads(s, parse_float=parse_float) def loads(s: str, *, parse_float: ParseFloat = float) -> Dict[str, Any]: # noqa: C901 """Parse TOML from a string.""" # The spec allows converting "\r\n" to "\n", even in string # literals. Let's do so to simplify parsing. src = s.replace("\r\n", "\n") pos = 0 out = Output(NestedDict(), Flags()) header: Key = () # Parse one statement at a time # (typically means one line in TOML source) while True: # 1. Skip line leading whitespace pos = skip_chars(src, pos, TOML_WS) # 2. Parse rules. Expect one of the following: # - end of file # - end of line # - comment # - key/value pair # - append dict to list (and move to its namespace) # - create dict (and move to its namespace) # Skip trailing whitespace when applicable. try: char = src[pos] except IndexError: break if char == "\n": pos += 1 continue if char in KEY_INITIAL_CHARS: pos = key_value_rule(src, pos, out, header, parse_float) pos = skip_chars(src, pos, TOML_WS) elif char == "[": try: second_char: Optional[str] = src[pos + 1] except IndexError: second_char = None if second_char == "[": pos, header = create_list_rule(src, pos, out) else: pos, header = create_dict_rule(src, pos, out) pos = skip_chars(src, pos, TOML_WS) elif char != "#": raise suffixed_err(src, pos, "Invalid statement") # 3. Skip comment pos = skip_comment(src, pos) # 4. Expect end of line or end of file try: char = src[pos] except IndexError: break if char != "\n": raise suffixed_err(src, pos, "Expected newline or end of document after a statement") pos += 1 return out.data.dict class Flags: """Flags that map to parsed keys/namespaces.""" # Marks an immutable namespace (inline array or inline table). FROZEN = 0 # Marks a nest that has been explicitly created and can no longer # be opened using the "[table]" syntax. EXPLICIT_NEST = 1 def __init__(self) -> None: self._flags: Dict[str, dict] = {} def unset_all(self, key: Key) -> None: cont = self._flags for k in key[:-1]: if k not in cont: return cont = cont[k]["nested"] cont.pop(key[-1], None) def set_for_relative_key(self, head_key: Key, rel_key: Key, flag: int) -> None: cont = self._flags for k in head_key: if k not in cont: cont[k] = {"flags": set(), "recursive_flags": set(), "nested": {}} cont = cont[k]["nested"] for k in rel_key: if k in cont: cont[k]["flags"].add(flag) else: cont[k] = {"flags": {flag}, "recursive_flags": set(), "nested": {}} cont = cont[k]["nested"] def set(self, key: Key, flag: int, *, recursive: bool) -> None: # noqa: A003 cont = self._flags key_parent, key_stem = key[:-1], key[-1] for k in key_parent: if k not in cont: cont[k] = {"flags": set(), "recursive_flags": set(), "nested": {}} cont = cont[k]["nested"] if key_stem not in cont: cont[key_stem] = {"flags": set(), "recursive_flags": set(), "nested": {}} cont[key_stem]["recursive_flags" if recursive else "flags"].add(flag) def is_(self, key: Key, flag: int) -> bool: if not key: return False # document root has no flags cont = self._flags for k in key[:-1]: if k not in cont: return False inner_cont = cont[k] if flag in inner_cont["recursive_flags"]: return True cont = inner_cont["nested"] key_stem = key[-1] if key_stem in cont: cont = cont[key_stem] return flag in cont["flags"] or flag in cont["recursive_flags"] return False class NestedDict: def __init__(self) -> None: # The parsed content of the TOML document self.dict: Dict[str, Any] = {} def get_or_create_nest( self, key: Key, *, access_lists: bool = True, ) -> dict: cont: Any = self.dict for k in key: if k not in cont: cont[k] = {} cont = cont[k] if access_lists and isinstance(cont, list): cont = cont[-1] if not isinstance(cont, dict): raise KeyError("There is no nest behind this key") return cont def append_nest_to_list(self, key: Key) -> None: cont = self.get_or_create_nest(key[:-1]) last_key = key[-1] if last_key in cont: list_ = cont[last_key] if not isinstance(list_, list): raise KeyError("An object other than list found behind this key") list_.append({}) else: cont[last_key] = [{}] class Output(NamedTuple): data: NestedDict flags: Flags def skip_chars(src: str, pos: Pos, chars: Iterable[str]) -> Pos: try: while src[pos] in chars: pos += 1 except IndexError: pass return pos def skip_until( src: str, pos: Pos, expect: str, *, error_on: FrozenSet[str], error_on_eof: bool, ) -> Pos: try: new_pos = src.index(expect, pos) except ValueError: new_pos = len(src) if error_on_eof: raise suffixed_err(src, new_pos, f'Expected "{expect!r}"') if not error_on.isdisjoint(src[pos:new_pos]): while src[pos] not in error_on: pos += 1 raise suffixed_err(src, pos, f'Found invalid character "{src[pos]!r}"') return new_pos def skip_comment(src: str, pos: Pos) -> Pos: try: char: Optional[str] = src[pos] except IndexError: char = None if char == "#": return skip_until(src, pos + 1, "\n", error_on=ILLEGAL_COMMENT_CHARS, error_on_eof=False) return pos def skip_comments_and_array_ws(src: str, pos: Pos) -> Pos: while True: pos_before_skip = pos pos = skip_chars(src, pos, TOML_WS_AND_NEWLINE) pos = skip_comment(src, pos) if pos == pos_before_skip: return pos def create_dict_rule(src: str, pos: Pos, out: Output) -> Tuple[Pos, Key]: pos += 1 # Skip "[" pos = skip_chars(src, pos, TOML_WS) pos, key = parse_key(src, pos) if out.flags.is_(key, Flags.EXPLICIT_NEST) or out.flags.is_(key, Flags.FROZEN): raise suffixed_err(src, pos, f"Can not declare {key} twice") out.flags.set(key, Flags.EXPLICIT_NEST, recursive=False) try: out.data.get_or_create_nest(key) except KeyError: raise suffixed_err(src, pos, "Can not overwrite a value") if not src.startswith("]", pos): raise suffixed_err(src, pos, 'Expected "]" at the end of a table declaration') return pos + 1, key def create_list_rule(src: str, pos: Pos, out: Output) -> Tuple[Pos, Key]: pos += 2 # Skip "[[" pos = skip_chars(src, pos, TOML_WS) pos, key = parse_key(src, pos) if out.flags.is_(key, Flags.FROZEN): raise suffixed_err(src, pos, f"Can not mutate immutable namespace {key}") # Free the namespace now that it points to another empty list item... out.flags.unset_all(key) # ...but this key precisely is still prohibited from table declaration out.flags.set(key, Flags.EXPLICIT_NEST, recursive=False) try: out.data.append_nest_to_list(key) except KeyError: raise suffixed_err(src, pos, "Can not overwrite a value") if not src.startswith("]]", pos): raise suffixed_err(src, pos, 'Expected "]]" at the end of an array declaration') return pos + 2, key def key_value_rule(src: str, pos: Pos, out: Output, header: Key, parse_float: ParseFloat) -> Pos: pos, key, value = parse_key_value_pair(src, pos, parse_float) key_parent, key_stem = key[:-1], key[-1] abs_key_parent = header + key_parent if out.flags.is_(abs_key_parent, Flags.FROZEN): raise suffixed_err(src, pos, f"Can not mutate immutable namespace {abs_key_parent}") # Containers in the relative path can't be opened with the table syntax after this out.flags.set_for_relative_key(header, key, Flags.EXPLICIT_NEST) try: nest = out.data.get_or_create_nest(abs_key_parent) except KeyError: raise suffixed_err(src, pos, "Can not overwrite a value") if key_stem in nest: raise suffixed_err(src, pos, "Can not overwrite a value") # Mark inline table and array namespaces recursively immutable if isinstance(value, (dict, list)): out.flags.set(header + key, Flags.FROZEN, recursive=True) nest[key_stem] = value return pos def parse_key_value_pair(src: str, pos: Pos, parse_float: ParseFloat) -> Tuple[Pos, Key, Any]: pos, key = parse_key(src, pos) try: char: Optional[str] = src[pos] except IndexError: char = None if char != "=": raise suffixed_err(src, pos, 'Expected "=" after a key in a key/value pair') pos += 1 pos = skip_chars(src, pos, TOML_WS) pos, value = parse_value(src, pos, parse_float) return pos, key, value def parse_key(src: str, pos: Pos) -> Tuple[Pos, Key]: pos, key_part = parse_key_part(src, pos) key: Key = (key_part,) pos = skip_chars(src, pos, TOML_WS) while True: try: char: Optional[str] = src[pos] except IndexError: char = None if char != ".": return pos, key pos += 1 pos = skip_chars(src, pos, TOML_WS) pos, key_part = parse_key_part(src, pos) key += (key_part,) pos = skip_chars(src, pos, TOML_WS) def parse_key_part(src: str, pos: Pos) -> Tuple[Pos, str]: try: char: Optional[str] = src[pos] except IndexError: char = None if char in BARE_KEY_CHARS: start_pos = pos pos = skip_chars(src, pos, BARE_KEY_CHARS) return pos, src[start_pos:pos] if char == "'": return parse_literal_str(src, pos) if char == '"': return parse_one_line_basic_str(src, pos) raise suffixed_err(src, pos, "Invalid initial character for a key part") def parse_one_line_basic_str(src: str, pos: Pos) -> Tuple[Pos, str]: pos += 1 return parse_basic_str(src, pos, multiline=False) def parse_array(src: str, pos: Pos, parse_float: ParseFloat) -> Tuple[Pos, list]: pos += 1 array: list = [] pos = skip_comments_and_array_ws(src, pos) if src.startswith("]", pos): return pos + 1, array while True: pos, val = parse_value(src, pos, parse_float) array.append(val) pos = skip_comments_and_array_ws(src, pos) c = src[pos : pos + 1] if c == "]": return pos + 1, array if c != ",": raise suffixed_err(src, pos, "Unclosed array") pos += 1 pos = skip_comments_and_array_ws(src, pos) if src.startswith("]", pos): return pos + 1, array def parse_inline_table(src: str, pos: Pos, parse_float: ParseFloat) -> Tuple[Pos, dict]: pos += 1 nested_dict = NestedDict() flags = Flags() pos = skip_chars(src, pos, TOML_WS) if src.startswith("}", pos): return pos + 1, nested_dict.dict while True: pos, key, value = parse_key_value_pair(src, pos, parse_float) key_parent, key_stem = key[:-1], key[-1] if flags.is_(key, Flags.FROZEN): raise suffixed_err(src, pos, f"Can not mutate immutable namespace {key}") try: nest = nested_dict.get_or_create_nest(key_parent, access_lists=False) except KeyError: raise suffixed_err(src, pos, "Can not overwrite a value") if key_stem in nest: raise suffixed_err(src, pos, f'Duplicate inline table key "{key_stem}"') nest[key_stem] = value pos = skip_chars(src, pos, TOML_WS) c = src[pos : pos + 1] if c == "}": return pos + 1, nested_dict.dict if c != ",": raise suffixed_err(src, pos, "Unclosed inline table") if isinstance(value, (dict, list)): flags.set(key, Flags.FROZEN, recursive=True) pos += 1 pos = skip_chars(src, pos, TOML_WS) def parse_basic_str_escape( # noqa: C901 src: str, pos: Pos, *, multiline: bool = False ) -> Tuple[Pos, str]: escape_id = src[pos : pos + 2] pos += 2 if multiline and escape_id in {"\\ ", "\\\t", "\\\n"}: # Skip whitespace until next non-whitespace character or end of # the doc. Error if non-whitespace is found before newline. if escape_id != "\\\n": pos = skip_chars(src, pos, TOML_WS) try: char = src[pos] except IndexError: return pos, "" if char != "\n": raise suffixed_err(src, pos, 'Unescaped "\\" in a string') pos += 1 pos = skip_chars(src, pos, TOML_WS_AND_NEWLINE) return pos, "" if escape_id == "\\u": return parse_hex_char(src, pos, 4) if escape_id == "\\U": return parse_hex_char(src, pos, 8) try: return pos, BASIC_STR_ESCAPE_REPLACEMENTS[escape_id] except KeyError: if len(escape_id) != 2: raise suffixed_err(src, pos, "Unterminated string") raise suffixed_err(src, pos, 'Unescaped "\\" in a string') def parse_basic_str_escape_multiline(src: str, pos: Pos) -> Tuple[Pos, str]: return parse_basic_str_escape(src, pos, multiline=True) def parse_hex_char(src: str, pos: Pos, hex_len: int) -> Tuple[Pos, str]: hex_str = src[pos : pos + hex_len] if len(hex_str) != hex_len or not HEXDIGIT_CHARS.issuperset(hex_str): raise suffixed_err(src, pos, "Invalid hex value") pos += hex_len hex_int = int(hex_str, 16) if not is_unicode_scalar_value(hex_int): raise suffixed_err(src, pos, "Escaped character is not a Unicode scalar value") return pos, chr(hex_int) def parse_literal_str(src: str, pos: Pos) -> Tuple[Pos, str]: pos += 1 # Skip starting apostrophe start_pos = pos pos = skip_until(src, pos, "'", error_on=ILLEGAL_LITERAL_STR_CHARS, error_on_eof=True) return pos + 1, src[start_pos:pos] # Skip ending apostrophe def parse_multiline_str(src: str, pos: Pos, *, literal: bool) -> Tuple[Pos, str]: pos += 3 if src.startswith("\n", pos): pos += 1 if literal: delim = "'" end_pos = skip_until( src, pos, "'''", error_on=ILLEGAL_MULTILINE_LITERAL_STR_CHARS, error_on_eof=True, ) result = src[pos:end_pos] pos = end_pos + 3 else: delim = '"' pos, result = parse_basic_str(src, pos, multiline=True) # Add at maximum two extra apostrophes/quotes if the end sequence # is 4 or 5 chars long instead of just 3. if not src.startswith(delim, pos): return pos, result pos += 1 if not src.startswith(delim, pos): return pos, result + delim pos += 1 return pos, result + (delim * 2) def parse_basic_str(src: str, pos: Pos, *, multiline: bool) -> Tuple[Pos, str]: if multiline: error_on = ILLEGAL_MULTILINE_BASIC_STR_CHARS parse_escapes = parse_basic_str_escape_multiline else: error_on = ILLEGAL_BASIC_STR_CHARS parse_escapes = parse_basic_str_escape result = "" start_pos = pos while True: try: char = src[pos] except IndexError: raise suffixed_err(src, pos, "Unterminated string") if char == '"': if not multiline: return pos + 1, result + src[start_pos:pos] if src.startswith('"""', pos): return pos + 3, result + src[start_pos:pos] pos += 1 continue if char == "\\": result += src[start_pos:pos] pos, parsed_escape = parse_escapes(src, pos) result += parsed_escape start_pos = pos continue if char in error_on: raise suffixed_err(src, pos, f'Illegal character "{char!r}"') pos += 1 def parse_value(src: str, pos: Pos, parse_float: ParseFloat) -> Tuple[Pos, Any]: # noqa: C901 try: char: Optional[str] = src[pos] except IndexError: char = None # Basic strings if char == '"': if src.startswith('"""', pos): return parse_multiline_str(src, pos, literal=False) return parse_one_line_basic_str(src, pos) # Literal strings if char == "'": if src.startswith("'''", pos): return parse_multiline_str(src, pos, literal=True) return parse_literal_str(src, pos) # Booleans if char == "t": if src.startswith("true", pos): return pos + 4, True if char == "f": if src.startswith("false", pos): return pos + 5, False # Dates and times datetime_match = RE_DATETIME.match(src, pos) if datetime_match: try: datetime_obj = match_to_datetime(datetime_match) except ValueError: raise suffixed_err(src, pos, "Invalid date or datetime") return datetime_match.end(), datetime_obj localtime_match = RE_LOCALTIME.match(src, pos) if localtime_match: return localtime_match.end(), match_to_localtime(localtime_match) # Integers and "normal" floats. # The regex will greedily match any type starting with a decimal # char, so needs to be located after handling of dates and times. number_match = RE_NUMBER.match(src, pos) if number_match: return number_match.end(), match_to_number(number_match, parse_float) # Arrays if char == "[": return parse_array(src, pos, parse_float) # Inline tables if char == "{": return parse_inline_table(src, pos, parse_float) # Special floats first_three = src[pos : pos + 3] if first_three in {"inf", "nan"}: return pos + 3, parse_float(first_three) first_four = src[pos : pos + 4] if first_four in {"-inf", "+inf", "-nan", "+nan"}: return pos + 4, parse_float(first_four) raise suffixed_err(src, pos, "Invalid value") def suffixed_err(src: str, pos: Pos, msg: str) -> TOMLDecodeError: """Return a `TOMLDecodeError` where error message is suffixed with coordinates in source.""" def coord_repr(src: str, pos: Pos) -> str: if pos >= len(src): return "end of document" line = src.count("\n", 0, pos) + 1 if line == 1: column = pos + 1 else: column = pos - src.rindex("\n", 0, pos) return f"line {line}, column {column}" return TOMLDecodeError(f"{msg} (at {coord_repr(src, pos)})") def is_unicode_scalar_value(codepoint: int) -> bool: return (0 <= codepoint <= 55295) or (57344 <= codepoint <= 1114111) isort-6.0.1/isort/_vendored/tomli/_re.py0000644000000000000000000000542113615410400015150 0ustar00import re from datetime import date, datetime, time, timedelta, timezone, tzinfo from functools import lru_cache from typing import TYPE_CHECKING, Any, Optional, Union if TYPE_CHECKING: from tomli._parser import ParseFloat # E.g. # - 00:32:00.999999 # - 00:32:00 _TIME_RE_STR = r"([01][0-9]|2[0-3]):([0-5][0-9]):([0-5][0-9])(?:\.([0-9]{1,6})[0-9]*)?" RE_NUMBER = re.compile( r""" 0 (?: x[0-9A-Fa-f](?:_?[0-9A-Fa-f])* # hex | b[01](?:_?[01])* # bin | o[0-7](?:_?[0-7])* # oct ) | [+-]?(?:0|[1-9](?:_?[0-9])*) # dec, integer part (?P (?:\.[0-9](?:_?[0-9])*)? # optional fractional part (?:[eE][+-]?[0-9](?:_?[0-9])*)? # optional exponent part ) """, flags=re.VERBOSE, ) RE_LOCALTIME = re.compile(_TIME_RE_STR) RE_DATETIME = re.compile( rf""" ([0-9]{{4}})-(0[1-9]|1[0-2])-(0[1-9]|[12][0-9]|3[01]) # date, e.g. 1988-10-27 (?: [T ] {_TIME_RE_STR} (?:(Z)|([+-])([01][0-9]|2[0-3]):([0-5][0-9]))? # optional time offset )? """, flags=re.VERBOSE, ) def match_to_datetime(match: "re.Match") -> Union[datetime, date]: """Convert a `RE_DATETIME` match to `datetime.datetime` or `datetime.date`. Raises ValueError if the match does not correspond to a valid date or datetime. """ ( year_str, month_str, day_str, hour_str, minute_str, sec_str, micros_str, zulu_time, offset_sign_str, offset_hour_str, offset_minute_str, ) = match.groups() year, month, day = int(year_str), int(month_str), int(day_str) if hour_str is None: return date(year, month, day) hour, minute, sec = int(hour_str), int(minute_str), int(sec_str) micros = int(micros_str.ljust(6, "0")) if micros_str else 0 if offset_sign_str: tz: Optional[tzinfo] = cached_tz(offset_hour_str, offset_minute_str, offset_sign_str) elif zulu_time: tz = timezone.utc else: # local date-time tz = None return datetime(year, month, day, hour, minute, sec, micros, tzinfo=tz) @lru_cache(maxsize=None) def cached_tz(hour_str: str, minute_str: str, sign_str: str) -> timezone: sign = 1 if sign_str == "+" else -1 return timezone( timedelta( hours=sign * int(hour_str), minutes=sign * int(minute_str), ) ) def match_to_localtime(match: "re.Match") -> time: hour_str, minute_str, sec_str, micros_str = match.groups() micros = int(micros_str.ljust(6, "0")) if micros_str else 0 return time(int(hour_str), int(minute_str), int(sec_str), micros) def match_to_number(match: "re.Match", parse_float: "ParseFloat") -> Any: if match.group("floatpart"): return parse_float(match.group()) return int(match.group(), 0) isort-6.0.1/isort/_vendored/tomli/py.typed0000644000000000000000000000003213615410400015521 0ustar00# Marker file for PEP 561 isort-6.0.1/isort/deprecated/__init__.py0000644000000000000000000000000013615410400015135 0ustar00isort-6.0.1/isort/deprecated/finders.py0000644000000000000000000003374313615410400015054 0ustar00"""Finders try to find right section for passed module name""" import importlib.machinery import inspect import os import os.path import re import sys import sysconfig from abc import ABCMeta, abstractmethod from contextlib import contextmanager from fnmatch import fnmatch from functools import lru_cache from glob import glob from pathlib import Path from typing import Dict, Iterable, Iterator, List, Optional, Pattern, Sequence, Tuple, Type from isort import sections from isort.settings import KNOWN_SECTION_MAPPING, Config from isort.utils import exists_case_sensitive try: from pipreqs import pipreqs # type: ignore except ImportError: pipreqs = None try: from pip_api import parse_requirements # type: ignore except ImportError: parse_requirements = None # type: ignore[assignment] @contextmanager def chdir(path: str) -> Iterator[None]: """Context manager for changing dir and restoring previous workdir after exit.""" curdir = os.getcwd() os.chdir(path) try: yield finally: os.chdir(curdir) class BaseFinder(metaclass=ABCMeta): def __init__(self, config: Config) -> None: self.config = config @abstractmethod def find(self, module_name: str) -> Optional[str]: raise NotImplementedError class ForcedSeparateFinder(BaseFinder): def find(self, module_name: str) -> Optional[str]: for forced_separate in self.config.forced_separate: # Ensure all forced_separate patterns will match to end of string path_glob = forced_separate if not forced_separate.endswith("*"): path_glob = f"{forced_separate}*" if fnmatch(module_name, path_glob) or fnmatch(module_name, "." + path_glob): return forced_separate return None class LocalFinder(BaseFinder): def find(self, module_name: str) -> Optional[str]: if module_name.startswith("."): return "LOCALFOLDER" return None class KnownPatternFinder(BaseFinder): def __init__(self, config: Config) -> None: super().__init__(config) self.known_patterns: List[Tuple[Pattern[str], str]] = [] for placement in reversed(config.sections): known_placement = KNOWN_SECTION_MAPPING.get(placement, placement).lower() config_key = f"known_{known_placement}" known_patterns = list( getattr(self.config, config_key, self.config.known_other.get(known_placement, [])) ) known_patterns = [ pattern for known_pattern in known_patterns for pattern in self._parse_known_pattern(known_pattern) ] for known_pattern in known_patterns: regexp = "^" + known_pattern.replace("*", ".*").replace("?", ".?") + "$" self.known_patterns.append((re.compile(regexp), placement)) def _parse_known_pattern(self, pattern: str) -> List[str]: """Expand pattern if identified as a directory and return found sub packages""" if pattern.endswith(os.path.sep): patterns = [ filename for filename in os.listdir(os.path.join(self.config.directory, pattern)) if os.path.isdir(os.path.join(self.config.directory, pattern, filename)) ] else: patterns = [pattern] return patterns def find(self, module_name: str) -> Optional[str]: # Try to find most specific placement instruction match (if any) parts = module_name.split(".") module_names_to_check = (".".join(parts[:first_k]) for first_k in range(len(parts), 0, -1)) for module_name_to_check in module_names_to_check: for pattern, placement in self.known_patterns: if pattern.match(module_name_to_check): return placement return None class PathFinder(BaseFinder): def __init__(self, config: Config, path: str = ".") -> None: super().__init__(config) # restore the original import path (i.e. not the path to bin/isort) root_dir = os.path.abspath(path) src_dir = f"{root_dir}/src" self.paths = [root_dir, src_dir] # virtual env self.virtual_env = self.config.virtual_env or os.environ.get("VIRTUAL_ENV") if self.virtual_env: self.virtual_env = os.path.realpath(self.virtual_env) self.virtual_env_src = "" if self.virtual_env: self.virtual_env_src = f"{self.virtual_env}/src/" for venv_path in glob(f"{self.virtual_env}/lib/python*/site-packages"): if venv_path not in self.paths: self.paths.append(venv_path) for nested_venv_path in glob(f"{self.virtual_env}/lib/python*/*/site-packages"): if nested_venv_path not in self.paths: self.paths.append(nested_venv_path) for venv_src_path in glob(f"{self.virtual_env}/src/*"): if os.path.isdir(venv_src_path): self.paths.append(venv_src_path) # conda self.conda_env = self.config.conda_env or os.environ.get("CONDA_PREFIX") or "" if self.conda_env: self.conda_env = os.path.realpath(self.conda_env) for conda_path in glob(f"{self.conda_env}/lib/python*/site-packages"): if conda_path not in self.paths: self.paths.append(conda_path) for nested_conda_path in glob(f"{self.conda_env}/lib/python*/*/site-packages"): if nested_conda_path not in self.paths: self.paths.append(nested_conda_path) # handle case-insensitive paths on windows self.stdlib_lib_prefix = os.path.normcase(sysconfig.get_paths()["stdlib"]) if self.stdlib_lib_prefix not in self.paths: self.paths.append(self.stdlib_lib_prefix) # add system paths for system_path in sys.path[1:]: if system_path not in self.paths: self.paths.append(system_path) def find(self, module_name: str) -> Optional[str]: for prefix in self.paths: package_path = "/".join((prefix, module_name.split(".")[0])) path_obj = Path(package_path).resolve() is_module = ( exists_case_sensitive(package_path + ".py") or any( exists_case_sensitive(package_path + ext_suffix) for ext_suffix in importlib.machinery.EXTENSION_SUFFIXES ) or exists_case_sensitive(package_path + "/__init__.py") ) is_package = exists_case_sensitive(package_path) and os.path.isdir(package_path) if is_module or is_package: if ( "site-packages" in prefix or "dist-packages" in prefix or (self.virtual_env and self.virtual_env_src in prefix) ): return sections.THIRDPARTY if os.path.normcase(prefix) == self.stdlib_lib_prefix: return sections.STDLIB if self.conda_env and self.conda_env in prefix: return sections.THIRDPARTY for src_path in self.config.src_paths: if src_path in path_obj.parents and not self.config.is_skipped(path_obj): return sections.FIRSTPARTY if os.path.normcase(prefix).startswith(self.stdlib_lib_prefix): return sections.STDLIB # pragma: no cover - edge case for one OS. Hard to test. return self.config.default_section return None class ReqsBaseFinder(BaseFinder): enabled = False def __init__(self, config: Config, path: str = ".") -> None: super().__init__(config) self.path = path if self.enabled: self.mapping = self._load_mapping() self.names = self._load_names() @abstractmethod def _get_names(self, path: str) -> Iterator[str]: raise NotImplementedError @abstractmethod def _get_files_from_dir(self, path: str) -> Iterator[str]: raise NotImplementedError @staticmethod def _load_mapping() -> Optional[Dict[str, str]]: """Return list of mappings `package_name -> module_name` Example: django-haystack -> haystack """ if not pipreqs: return None path = os.path.dirname(inspect.getfile(pipreqs)) path = os.path.join(path, "mapping") with open(path) as f: mappings: Dict[str, str] = {} # pypi_name: import_name for line in f: import_name, _, pypi_name = line.strip().partition(":") mappings[pypi_name] = import_name return mappings def _load_names(self) -> List[str]: """Return list of thirdparty modules from requirements""" names: List[str] = [] for path in self._get_files(): names.extend(self._normalize_name(name) for name in self._get_names(path)) return names @staticmethod def _get_parents(path: str) -> Iterator[str]: prev = "" while path != prev: prev = path yield path path = os.path.dirname(path) def _get_files(self) -> Iterator[str]: """Return paths to all requirements files""" path = os.path.abspath(self.path) if os.path.isfile(path): path = os.path.dirname(path) for path in self._get_parents(path): # noqa yield from self._get_files_from_dir(path) def _normalize_name(self, name: str) -> str: """Convert package name to module name Examples: Django -> django django-haystack -> django_haystack Flask-RESTFul -> flask_restful """ if self.mapping: name = self.mapping.get(name.replace("-", "_"), name) return name.lower().replace("-", "_") def find(self, module_name: str) -> Optional[str]: # required lib not installed yet if not self.enabled: return None module_name, _sep, _submodules = module_name.partition(".") module_name = module_name.lower() if not module_name: return None for name in self.names: if module_name == name: return sections.THIRDPARTY return None class RequirementsFinder(ReqsBaseFinder): exts = (".txt", ".in") enabled = bool(parse_requirements) def _get_files_from_dir(self, path: str) -> Iterator[str]: """Return paths to requirements files from passed dir.""" yield from self._get_files_from_dir_cached(path) @classmethod @lru_cache(maxsize=16) def _get_files_from_dir_cached(cls, path: str) -> List[str]: results: List[str] = [] for fname in os.listdir(path): if "requirements" not in fname: continue full_path = os.path.join(path, fname) # *requirements*/*.{txt,in} if os.path.isdir(full_path): for subfile_name in os.listdir(full_path): results.extend( os.path.join(full_path, subfile_name) for ext in cls.ext # type: ignore[attr-defined] if subfile_name.endswith(ext) ) continue # *requirements*.{txt,in} if os.path.isfile(full_path): for ext in cls.exts: if fname.endswith(ext): results.append(full_path) break return results def _get_names(self, path: str) -> Iterator[str]: """Load required packages from path to requirements file""" yield from self._get_names_cached(path) @classmethod @lru_cache(maxsize=16) def _get_names_cached(cls, path: str) -> List[str]: result: List[str] = [] with chdir(os.path.dirname(path)): requirements = parse_requirements(Path(path)) result.extend(req.name for req in requirements.values() if req.name) return result class DefaultFinder(BaseFinder): def find(self, module_name: str) -> Optional[str]: return self.config.default_section class FindersManager: _default_finders_classes: Sequence[Type[BaseFinder]] = ( ForcedSeparateFinder, LocalFinder, KnownPatternFinder, PathFinder, RequirementsFinder, DefaultFinder, ) def __init__( self, config: Config, finder_classes: Optional[Iterable[Type[BaseFinder]]] = None ) -> None: self.verbose: bool = config.verbose if finder_classes is None: finder_classes = self._default_finders_classes finders: List[BaseFinder] = [] for finder_cls in finder_classes: try: finders.append(finder_cls(config)) except Exception as exception: # if one finder fails to instantiate isort can continue using the rest if self.verbose: print( ( f"{finder_cls.__name__} encountered an error ({exception}) during " "instantiation and cannot be used" ) ) self.finders: Tuple[BaseFinder, ...] = tuple(finders) def find(self, module_name: str) -> Optional[str]: for finder in self.finders: try: section = finder.find(module_name) if section is not None: return section except Exception as exception: # isort has to be able to keep trying to identify the correct # import section even if one approach fails if self.verbose: print( f"{finder.__class__.__name__} encountered an error ({exception}) while " f"trying to identify the {module_name} module" ) return None isort-6.0.1/isort/stdlibs/__init__.py0000644000000000000000000000041413615410400014512 0ustar00from . import all as _all from . import py2, py3, py27, py36, py37, py38, py39, py310, py311, py312, py313 __all__ = ( "_all", "py2", "py3", "py27", "py36", "py37", "py38", "py39", "py310", "py311", "py312", "py313", ) isort-6.0.1/isort/stdlibs/all.py0000644000000000000000000000007113615410400013522 0ustar00from . import py2, py3 stdlib = py2.stdlib | py3.stdlib isort-6.0.1/isort/stdlibs/py2.py0000644000000000000000000000005113615410400013462 0ustar00from . import py27 stdlib = py27.stdlib isort-6.0.1/isort/stdlibs/py27.py0000644000000000000000000001063013615410400013555 0ustar00""" File contains the standard library of Python 2.7. DO NOT EDIT. If the standard library changes, a new list should be created using the mkstdlibs.py script. """ stdlib = { "AL", "BaseHTTPServer", "Bastion", "CGIHTTPServer", "Carbon", "ColorPicker", "ConfigParser", "Cookie", "DEVICE", "DocXMLRPCServer", "EasyDialogs", "FL", "FrameWork", "GL", "HTMLParser", "MacOS", "MimeWriter", "MiniAEFrame", "Nav", "PixMapWrapper", "Queue", "SUNAUDIODEV", "ScrolledText", "SimpleHTTPServer", "SimpleXMLRPCServer", "SocketServer", "StringIO", "Tix", "Tkinter", "UserDict", "UserList", "UserString", "W", "__builtin__", "_ast", "_winreg", "abc", "aepack", "aetools", "aetypes", "aifc", "al", "anydbm", "applesingle", "argparse", "array", "ast", "asynchat", "asyncore", "atexit", "audioop", "autoGIL", "base64", "bdb", "binascii", "binhex", "bisect", "bsddb", "buildtools", "bz2", "cPickle", "cProfile", "cStringIO", "calendar", "cd", "cfmfile", "cgi", "cgitb", "chunk", "cmath", "cmd", "code", "codecs", "codeop", "collections", "colorsys", "commands", "compileall", "compiler", "contextlib", "cookielib", "copy", "copy_reg", "crypt", "csv", "ctypes", "curses", "datetime", "dbhash", "dbm", "decimal", "difflib", "dircache", "dis", "distutils", "dl", "doctest", "dumbdbm", "dummy_thread", "dummy_threading", "email", "encodings", "ensurepip", "errno", "exceptions", "fcntl", "filecmp", "fileinput", "findertools", "fl", "flp", "fm", "fnmatch", "formatter", "fpectl", "fpformat", "fractions", "ftplib", "functools", "future_builtins", "gc", "gdbm", "gensuitemodule", "getopt", "getpass", "gettext", "gl", "glob", "grp", "gzip", "hashlib", "heapq", "hmac", "hotshot", "htmlentitydefs", "htmllib", "httplib", "ic", "icopen", "imageop", "imaplib", "imgfile", "imghdr", "imp", "importlib", "imputil", "inspect", "io", "itertools", "jpeg", "json", "keyword", "lib2to3", "linecache", "locale", "logging", "macerrors", "macostools", "macpath", "macresource", "mailbox", "mailcap", "marshal", "math", "md5", "mhlib", "mimetools", "mimetypes", "mimify", "mmap", "modulefinder", "msilib", "msvcrt", "multifile", "multiprocessing", "mutex", "netrc", "new", "nis", "nntplib", "ntpath", "numbers", "operator", "optparse", "os", "ossaudiodev", "parser", "pdb", "pickle", "pickletools", "pipes", "pkgutil", "platform", "plistlib", "popen2", "poplib", "posix", "posixfile", "posixpath", "pprint", "profile", "pstats", "pty", "pwd", "py_compile", "pyclbr", "pydoc", "quopri", "random", "re", "readline", "resource", "rexec", "rfc822", "rlcompleter", "robotparser", "runpy", "sched", "select", "sets", "sgmllib", "sha", "shelve", "shlex", "shutil", "signal", "site", "smtpd", "smtplib", "sndhdr", "socket", "spwd", "sqlite3", "sre", "sre_compile", "sre_constants", "sre_parse", "ssl", "stat", "statvfs", "string", "stringprep", "struct", "subprocess", "sunau", "sunaudiodev", "symbol", "symtable", "sys", "sysconfig", "syslog", "tabnanny", "tarfile", "telnetlib", "tempfile", "termios", "test", "textwrap", "thread", "threading", "time", "timeit", "token", "tokenize", "trace", "traceback", "ttk", "tty", "turtle", "types", "unicodedata", "unittest", "urllib", "urllib2", "urlparse", "user", "uu", "uuid", "videoreader", "warnings", "wave", "weakref", "webbrowser", "whichdb", "winsound", "wsgiref", "xdrlib", "xml", "xmlrpclib", "zipfile", "zipimport", "zlib", } isort-6.0.1/isort/stdlibs/py3.py0000644000000000000000000000034113615410400013465 0ustar00from . import py36, py37, py38, py39, py310, py311, py312, py313 stdlib = ( py36.stdlib | py37.stdlib | py38.stdlib | py39.stdlib | py310.stdlib | py311.stdlib | py312.stdlib | py313.stdlib ) isort-6.0.1/isort/stdlibs/py310.py0000644000000000000000000000656013615410400013637 0ustar00""" File contains the standard library of Python 3.10. DO NOT EDIT. If the standard library changes, a new list should be created using the mkstdlibs.py script. """ stdlib = { "_ast", "abc", "aifc", "antigravity", "argparse", "array", "ast", "asynchat", "asyncio", "asyncore", "atexit", "audioop", "base64", "bdb", "binascii", "binhex", "bisect", "builtins", "bz2", "cProfile", "calendar", "cgi", "cgitb", "chunk", "cmath", "cmd", "code", "codecs", "codeop", "collections", "colorsys", "compileall", "concurrent", "configparser", "contextlib", "contextvars", "copy", "copyreg", "crypt", "csv", "ctypes", "curses", "dataclasses", "datetime", "dbm", "decimal", "difflib", "dis", "distutils", "doctest", "email", "encodings", "ensurepip", "enum", "errno", "faulthandler", "fcntl", "filecmp", "fileinput", "fnmatch", "fractions", "ftplib", "functools", "gc", "genericpath", "getopt", "getpass", "gettext", "glob", "graphlib", "grp", "gzip", "hashlib", "heapq", "hmac", "html", "http", "idlelib", "imaplib", "imghdr", "imp", "importlib", "inspect", "io", "ipaddress", "itertools", "json", "keyword", "lib2to3", "linecache", "locale", "logging", "lzma", "mailbox", "mailcap", "marshal", "math", "mimetypes", "mmap", "modulefinder", "msilib", "msvcrt", "multiprocessing", "netrc", "nis", "nntplib", "nt", "ntpath", "nturl2path", "numbers", "opcode", "operator", "optparse", "os", "ossaudiodev", "pathlib", "pdb", "pickle", "pickletools", "pipes", "pkgutil", "platform", "plistlib", "poplib", "posix", "posixpath", "pprint", "profile", "pstats", "pty", "pwd", "py_compile", "pyclbr", "pydoc", "pydoc_data", "pyexpat", "queue", "quopri", "random", "re", "readline", "reprlib", "resource", "rlcompleter", "runpy", "sched", "secrets", "select", "selectors", "shelve", "shlex", "shutil", "signal", "site", "smtpd", "smtplib", "sndhdr", "socket", "socketserver", "spwd", "sqlite3", "sre", "sre_compile", "sre_constants", "sre_parse", "ssl", "stat", "statistics", "string", "stringprep", "struct", "subprocess", "sunau", "symtable", "sys", "sysconfig", "syslog", "tabnanny", "tarfile", "telnetlib", "tempfile", "termios", "textwrap", "this", "threading", "time", "timeit", "tkinter", "token", "tokenize", "trace", "traceback", "tracemalloc", "tty", "turtle", "turtledemo", "types", "typing", "unicodedata", "unittest", "urllib", "uu", "uuid", "venv", "warnings", "wave", "weakref", "webbrowser", "winreg", "winsound", "wsgiref", "xdrlib", "xml", "xmlrpc", "xx", "xxlimited", "xxlimited_35", "xxsubtype", "zipapp", "zipfile", "zipimport", "zlib", "zoneinfo", } isort-6.0.1/isort/stdlibs/py311.py0000644000000000000000000000656113615410400013641 0ustar00""" File contains the standard library of Python 3.11. DO NOT EDIT. If the standard library changes, a new list should be created using the mkstdlibs.py script. """ stdlib = { "_ast", "abc", "aifc", "antigravity", "argparse", "array", "ast", "asynchat", "asyncio", "asyncore", "atexit", "audioop", "base64", "bdb", "binascii", "bisect", "builtins", "bz2", "cProfile", "calendar", "cgi", "cgitb", "chunk", "cmath", "cmd", "code", "codecs", "codeop", "collections", "colorsys", "compileall", "concurrent", "configparser", "contextlib", "contextvars", "copy", "copyreg", "crypt", "csv", "ctypes", "curses", "dataclasses", "datetime", "dbm", "decimal", "difflib", "dis", "distutils", "doctest", "email", "encodings", "ensurepip", "enum", "errno", "faulthandler", "fcntl", "filecmp", "fileinput", "fnmatch", "fractions", "ftplib", "functools", "gc", "genericpath", "getopt", "getpass", "gettext", "glob", "graphlib", "grp", "gzip", "hashlib", "heapq", "hmac", "html", "http", "idlelib", "imaplib", "imghdr", "imp", "importlib", "inspect", "io", "ipaddress", "itertools", "json", "keyword", "lib2to3", "linecache", "locale", "logging", "lzma", "mailbox", "mailcap", "marshal", "math", "mimetypes", "mmap", "modulefinder", "msilib", "msvcrt", "multiprocessing", "netrc", "nis", "nntplib", "nt", "ntpath", "nturl2path", "numbers", "opcode", "operator", "optparse", "os", "ossaudiodev", "pathlib", "pdb", "pickle", "pickletools", "pipes", "pkgutil", "platform", "plistlib", "poplib", "posix", "posixpath", "pprint", "profile", "pstats", "pty", "pwd", "py_compile", "pyclbr", "pydoc", "pydoc_data", "pyexpat", "queue", "quopri", "random", "re", "readline", "reprlib", "resource", "rlcompleter", "runpy", "sched", "secrets", "select", "selectors", "shelve", "shlex", "shutil", "signal", "site", "smtpd", "smtplib", "sndhdr", "socket", "socketserver", "spwd", "sqlite3", "sre", "sre_compile", "sre_constants", "sre_parse", "ssl", "stat", "statistics", "string", "stringprep", "struct", "subprocess", "sunau", "symtable", "sys", "sysconfig", "syslog", "tabnanny", "tarfile", "telnetlib", "tempfile", "termios", "textwrap", "this", "threading", "time", "timeit", "tkinter", "token", "tokenize", "tomllib", "trace", "traceback", "tracemalloc", "tty", "turtle", "turtledemo", "types", "typing", "unicodedata", "unittest", "urllib", "uu", "uuid", "venv", "warnings", "wave", "weakref", "webbrowser", "winreg", "winsound", "wsgiref", "xdrlib", "xml", "xmlrpc", "xx", "xxlimited", "xxlimited_35", "xxsubtype", "zipapp", "zipfile", "zipimport", "zlib", "zoneinfo", } isort-6.0.1/isort/stdlibs/py312.py0000644000000000000000000000645013615410400013637 0ustar00""" File contains the standard library of Python 3.12. DO NOT EDIT. If the standard library changes, a new list should be created using the mkstdlibs.py script. """ stdlib = { "_ast", "abc", "aifc", "antigravity", "argparse", "array", "ast", "asyncio", "atexit", "audioop", "base64", "bdb", "binascii", "bisect", "builtins", "bz2", "cProfile", "calendar", "cgi", "cgitb", "chunk", "cmath", "cmd", "code", "codecs", "codeop", "collections", "colorsys", "compileall", "concurrent", "configparser", "contextlib", "contextvars", "copy", "copyreg", "crypt", "csv", "ctypes", "curses", "dataclasses", "datetime", "dbm", "decimal", "difflib", "dis", "doctest", "email", "encodings", "ensurepip", "enum", "errno", "faulthandler", "fcntl", "filecmp", "fileinput", "fnmatch", "fractions", "ftplib", "functools", "gc", "genericpath", "getopt", "getpass", "gettext", "glob", "graphlib", "grp", "gzip", "hashlib", "heapq", "hmac", "html", "http", "idlelib", "imaplib", "imghdr", "importlib", "inspect", "io", "ipaddress", "itertools", "json", "keyword", "lib2to3", "linecache", "locale", "logging", "lzma", "mailbox", "mailcap", "marshal", "math", "mimetypes", "mmap", "modulefinder", "msilib", "msvcrt", "multiprocessing", "netrc", "nis", "nntplib", "nt", "ntpath", "nturl2path", "numbers", "opcode", "operator", "optparse", "os", "ossaudiodev", "pathlib", "pdb", "pickle", "pickletools", "pipes", "pkgutil", "platform", "plistlib", "poplib", "posix", "posixpath", "pprint", "profile", "pstats", "pty", "pwd", "py_compile", "pyclbr", "pydoc", "pydoc_data", "pyexpat", "queue", "quopri", "random", "re", "readline", "reprlib", "resource", "rlcompleter", "runpy", "sched", "secrets", "select", "selectors", "shelve", "shlex", "shutil", "signal", "site", "smtplib", "sndhdr", "socket", "socketserver", "spwd", "sqlite3", "sre", "sre_compile", "sre_constants", "sre_parse", "ssl", "stat", "statistics", "string", "stringprep", "struct", "subprocess", "sunau", "symtable", "sys", "sysconfig", "syslog", "tabnanny", "tarfile", "telnetlib", "tempfile", "termios", "textwrap", "this", "threading", "time", "timeit", "tkinter", "token", "tokenize", "tomllib", "trace", "traceback", "tracemalloc", "tty", "turtle", "turtledemo", "types", "typing", "unicodedata", "unittest", "urllib", "uu", "uuid", "venv", "warnings", "wave", "weakref", "webbrowser", "winreg", "winsound", "wsgiref", "xdrlib", "xml", "xmlrpc", "xx", "xxlimited", "xxlimited_35", "xxsubtype", "zipapp", "zipfile", "zipimport", "zlib", "zoneinfo", } isort-6.0.1/isort/stdlibs/py313.py0000644000000000000000000000602713615410400013640 0ustar00""" File contains the standard library of Python 3.13. DO NOT EDIT. If the standard library changes, a new list should be created using the mkstdlibs.py script. """ stdlib = { "_ast", "abc", "antigravity", "argparse", "array", "ast", "asyncio", "atexit", "base64", "bdb", "binascii", "bisect", "builtins", "bz2", "cProfile", "calendar", "cmath", "cmd", "code", "codecs", "codeop", "collections", "colorsys", "compileall", "concurrent", "configparser", "contextlib", "contextvars", "copy", "copyreg", "csv", "ctypes", "curses", "dataclasses", "datetime", "dbm", "decimal", "difflib", "dis", "doctest", "email", "encodings", "ensurepip", "enum", "errno", "faulthandler", "fcntl", "filecmp", "fileinput", "fnmatch", "fractions", "ftplib", "functools", "gc", "genericpath", "getopt", "getpass", "gettext", "glob", "graphlib", "grp", "gzip", "hashlib", "heapq", "hmac", "html", "http", "idlelib", "imaplib", "importlib", "inspect", "io", "ipaddress", "itertools", "json", "keyword", "linecache", "locale", "logging", "lzma", "mailbox", "marshal", "math", "mimetypes", "mmap", "modulefinder", "msvcrt", "multiprocessing", "netrc", "nt", "ntpath", "nturl2path", "numbers", "opcode", "operator", "optparse", "os", "pathlib", "pdb", "pickle", "pickletools", "pkgutil", "platform", "plistlib", "poplib", "posix", "posixpath", "pprint", "profile", "pstats", "pty", "pwd", "py_compile", "pyclbr", "pydoc", "pydoc_data", "pyexpat", "queue", "quopri", "random", "re", "readline", "reprlib", "resource", "rlcompleter", "runpy", "sched", "secrets", "select", "selectors", "shelve", "shlex", "shutil", "signal", "site", "smtplib", "socket", "socketserver", "sqlite3", "sre", "sre_compile", "sre_constants", "sre_parse", "ssl", "stat", "statistics", "string", "stringprep", "struct", "subprocess", "symtable", "sys", "sysconfig", "syslog", "tabnanny", "tarfile", "tempfile", "termios", "textwrap", "this", "threading", "time", "timeit", "tkinter", "token", "tokenize", "tomllib", "trace", "traceback", "tracemalloc", "tty", "turtle", "turtledemo", "types", "typing", "unicodedata", "unittest", "urllib", "uuid", "venv", "warnings", "wave", "weakref", "webbrowser", "winreg", "winsound", "wsgiref", "xml", "xmlrpc", "xx", "xxlimited", "xxlimited_35", "xxsubtype", "zipapp", "zipfile", "zipimport", "zlib", "zoneinfo", } isort-6.0.1/isort/stdlibs/py36.py0000644000000000000000000000635613615410400013567 0ustar00""" File contains the standard library of Python 3.6. DO NOT EDIT. If the standard library changes, a new list should be created using the mkstdlibs.py script. """ stdlib = { "_ast", "_dummy_thread", "_thread", "abc", "aifc", "argparse", "array", "ast", "asynchat", "asyncio", "asyncore", "atexit", "audioop", "base64", "bdb", "binascii", "binhex", "bisect", "builtins", "bz2", "cProfile", "calendar", "cgi", "cgitb", "chunk", "cmath", "cmd", "code", "codecs", "codeop", "collections", "colorsys", "compileall", "concurrent", "configparser", "contextlib", "copy", "copyreg", "crypt", "csv", "ctypes", "curses", "datetime", "dbm", "decimal", "difflib", "dis", "distutils", "doctest", "dummy_threading", "email", "encodings", "ensurepip", "enum", "errno", "faulthandler", "fcntl", "filecmp", "fileinput", "fnmatch", "formatter", "fpectl", "fractions", "ftplib", "functools", "gc", "getopt", "getpass", "gettext", "glob", "grp", "gzip", "hashlib", "heapq", "hmac", "html", "http", "imaplib", "imghdr", "imp", "importlib", "inspect", "io", "ipaddress", "itertools", "json", "keyword", "lib2to3", "linecache", "locale", "logging", "lzma", "macpath", "mailbox", "mailcap", "marshal", "math", "mimetypes", "mmap", "modulefinder", "msilib", "msvcrt", "multiprocessing", "netrc", "nis", "nntplib", "ntpath", "numbers", "operator", "optparse", "os", "ossaudiodev", "parser", "pathlib", "pdb", "pickle", "pickletools", "pipes", "pkgutil", "platform", "plistlib", "poplib", "posix", "posixpath", "pprint", "profile", "pstats", "pty", "pwd", "py_compile", "pyclbr", "pydoc", "queue", "quopri", "random", "re", "readline", "reprlib", "resource", "rlcompleter", "runpy", "sched", "secrets", "select", "selectors", "shelve", "shlex", "shutil", "signal", "site", "smtpd", "smtplib", "sndhdr", "socket", "socketserver", "spwd", "sqlite3", "sre", "sre_compile", "sre_constants", "sre_parse", "ssl", "stat", "statistics", "string", "stringprep", "struct", "subprocess", "sunau", "symbol", "symtable", "sys", "sysconfig", "syslog", "tabnanny", "tarfile", "telnetlib", "tempfile", "termios", "test", "textwrap", "threading", "time", "timeit", "tkinter", "token", "tokenize", "trace", "traceback", "tracemalloc", "tty", "turtle", "turtledemo", "types", "typing", "unicodedata", "unittest", "urllib", "uu", "uuid", "venv", "warnings", "wave", "weakref", "webbrowser", "winreg", "winsound", "wsgiref", "xdrlib", "xml", "xmlrpc", "zipapp", "zipfile", "zipimport", "zlib", } isort-6.0.1/isort/stdlibs/py37.py0000644000000000000000000000640613615410400013564 0ustar00""" File contains the standard library of Python 3.7. DO NOT EDIT. If the standard library changes, a new list should be created using the mkstdlibs.py script. """ stdlib = { "_ast", "_dummy_thread", "_thread", "abc", "aifc", "argparse", "array", "ast", "asynchat", "asyncio", "asyncore", "atexit", "audioop", "base64", "bdb", "binascii", "binhex", "bisect", "builtins", "bz2", "cProfile", "calendar", "cgi", "cgitb", "chunk", "cmath", "cmd", "code", "codecs", "codeop", "collections", "colorsys", "compileall", "concurrent", "configparser", "contextlib", "contextvars", "copy", "copyreg", "crypt", "csv", "ctypes", "curses", "dataclasses", "datetime", "dbm", "decimal", "difflib", "dis", "distutils", "doctest", "dummy_threading", "email", "encodings", "ensurepip", "enum", "errno", "faulthandler", "fcntl", "filecmp", "fileinput", "fnmatch", "formatter", "fractions", "ftplib", "functools", "gc", "getopt", "getpass", "gettext", "glob", "grp", "gzip", "hashlib", "heapq", "hmac", "html", "http", "imaplib", "imghdr", "imp", "importlib", "inspect", "io", "ipaddress", "itertools", "json", "keyword", "lib2to3", "linecache", "locale", "logging", "lzma", "macpath", "mailbox", "mailcap", "marshal", "math", "mimetypes", "mmap", "modulefinder", "msilib", "msvcrt", "multiprocessing", "netrc", "nis", "nntplib", "ntpath", "numbers", "operator", "optparse", "os", "ossaudiodev", "parser", "pathlib", "pdb", "pickle", "pickletools", "pipes", "pkgutil", "platform", "plistlib", "poplib", "posix", "posixpath", "pprint", "profile", "pstats", "pty", "pwd", "py_compile", "pyclbr", "pydoc", "queue", "quopri", "random", "re", "readline", "reprlib", "resource", "rlcompleter", "runpy", "sched", "secrets", "select", "selectors", "shelve", "shlex", "shutil", "signal", "site", "smtpd", "smtplib", "sndhdr", "socket", "socketserver", "spwd", "sqlite3", "sre", "sre_compile", "sre_constants", "sre_parse", "ssl", "stat", "statistics", "string", "stringprep", "struct", "subprocess", "sunau", "symbol", "symtable", "sys", "sysconfig", "syslog", "tabnanny", "tarfile", "telnetlib", "tempfile", "termios", "test", "textwrap", "threading", "time", "timeit", "tkinter", "token", "tokenize", "trace", "traceback", "tracemalloc", "tty", "turtle", "turtledemo", "types", "typing", "unicodedata", "unittest", "urllib", "uu", "uuid", "venv", "warnings", "wave", "weakref", "webbrowser", "winreg", "winsound", "wsgiref", "xdrlib", "xml", "xmlrpc", "zipapp", "zipfile", "zipimport", "zlib", } isort-6.0.1/isort/stdlibs/py38.py0000644000000000000000000000657713615410400013576 0ustar00""" File contains the standard library of Python 3.8. DO NOT EDIT. If the standard library changes, a new list should be created using the mkstdlibs.py script. """ stdlib = { "_ast", "abc", "aifc", "antigravity", "argparse", "array", "ast", "asynchat", "asyncio", "asyncore", "atexit", "audioop", "base64", "bdb", "binascii", "binhex", "bisect", "builtins", "bz2", "cProfile", "calendar", "cgi", "cgitb", "chunk", "cmath", "cmd", "code", "codecs", "codeop", "collections", "colorsys", "compileall", "concurrent", "configparser", "contextlib", "contextvars", "copy", "copyreg", "crypt", "csv", "ctypes", "curses", "dataclasses", "datetime", "dbm", "decimal", "difflib", "dis", "distutils", "doctest", "dummy_threading", "email", "encodings", "ensurepip", "enum", "errno", "faulthandler", "fcntl", "filecmp", "fileinput", "fnmatch", "formatter", "fractions", "ftplib", "functools", "gc", "genericpath", "getopt", "getpass", "gettext", "glob", "grp", "gzip", "hashlib", "heapq", "hmac", "html", "http", "idlelib", "imaplib", "imghdr", "imp", "importlib", "inspect", "io", "ipaddress", "itertools", "json", "keyword", "lib2to3", "linecache", "locale", "logging", "lzma", "mailbox", "mailcap", "marshal", "math", "mimetypes", "mmap", "modulefinder", "msilib", "msvcrt", "multiprocessing", "netrc", "nis", "nntplib", "nt", "ntpath", "nturl2path", "numbers", "opcode", "operator", "optparse", "os", "ossaudiodev", "parser", "pathlib", "pdb", "pickle", "pickletools", "pipes", "pkgutil", "platform", "plistlib", "poplib", "posix", "posixpath", "pprint", "profile", "pstats", "pty", "pwd", "py_compile", "pyclbr", "pydoc", "pydoc_data", "pyexpat", "queue", "quopri", "random", "re", "readline", "reprlib", "resource", "rlcompleter", "runpy", "sched", "secrets", "select", "selectors", "shelve", "shlex", "shutil", "signal", "site", "smtpd", "smtplib", "sndhdr", "socket", "socketserver", "spwd", "sqlite3", "sre", "sre_compile", "sre_constants", "sre_parse", "ssl", "stat", "statistics", "string", "stringprep", "struct", "subprocess", "sunau", "symbol", "symtable", "sys", "sysconfig", "syslog", "tabnanny", "tarfile", "telnetlib", "tempfile", "termios", "textwrap", "this", "threading", "time", "timeit", "tkinter", "token", "tokenize", "trace", "traceback", "tracemalloc", "tty", "turtle", "turtledemo", "types", "typing", "unicodedata", "unittest", "urllib", "uu", "uuid", "venv", "warnings", "wave", "weakref", "webbrowser", "winreg", "winsound", "wsgiref", "xdrlib", "xml", "xmlrpc", "xx", "xxlimited", "xxsubtype", "zipapp", "zipfile", "zipimport", "zlib", } isort-6.0.1/isort/stdlibs/py39.py0000644000000000000000000000661013615410400013563 0ustar00""" File contains the standard library of Python 3.9. DO NOT EDIT. If the standard library changes, a new list should be created using the mkstdlibs.py script. """ stdlib = { "_ast", "abc", "aifc", "antigravity", "argparse", "array", "ast", "asynchat", "asyncio", "asyncore", "atexit", "audioop", "base64", "bdb", "binascii", "binhex", "bisect", "builtins", "bz2", "cProfile", "calendar", "cgi", "cgitb", "chunk", "cmath", "cmd", "code", "codecs", "codeop", "collections", "colorsys", "compileall", "concurrent", "configparser", "contextlib", "contextvars", "copy", "copyreg", "crypt", "csv", "ctypes", "curses", "dataclasses", "datetime", "dbm", "decimal", "difflib", "dis", "distutils", "doctest", "email", "encodings", "ensurepip", "enum", "errno", "faulthandler", "fcntl", "filecmp", "fileinput", "fnmatch", "formatter", "fractions", "ftplib", "functools", "gc", "genericpath", "getopt", "getpass", "gettext", "glob", "graphlib", "grp", "gzip", "hashlib", "heapq", "hmac", "html", "http", "idlelib", "imaplib", "imghdr", "imp", "importlib", "inspect", "io", "ipaddress", "itertools", "json", "keyword", "lib2to3", "linecache", "locale", "logging", "lzma", "mailbox", "mailcap", "marshal", "math", "mimetypes", "mmap", "modulefinder", "msilib", "msvcrt", "multiprocessing", "netrc", "nis", "nntplib", "nt", "ntpath", "nturl2path", "numbers", "opcode", "operator", "optparse", "os", "ossaudiodev", "parser", "pathlib", "pdb", "pickle", "pickletools", "pipes", "pkgutil", "platform", "plistlib", "poplib", "posix", "posixpath", "pprint", "profile", "pstats", "pty", "pwd", "py_compile", "pyclbr", "pydoc", "pydoc_data", "pyexpat", "queue", "quopri", "random", "re", "readline", "reprlib", "resource", "rlcompleter", "runpy", "sched", "secrets", "select", "selectors", "shelve", "shlex", "shutil", "signal", "site", "smtpd", "smtplib", "sndhdr", "socket", "socketserver", "spwd", "sqlite3", "sre", "sre_compile", "sre_constants", "sre_parse", "ssl", "stat", "statistics", "string", "stringprep", "struct", "subprocess", "sunau", "symbol", "symtable", "sys", "sysconfig", "syslog", "tabnanny", "tarfile", "telnetlib", "tempfile", "termios", "textwrap", "this", "threading", "time", "timeit", "tkinter", "token", "tokenize", "trace", "traceback", "tracemalloc", "tty", "turtle", "turtledemo", "types", "typing", "unicodedata", "unittest", "urllib", "uu", "uuid", "venv", "warnings", "wave", "weakref", "webbrowser", "winreg", "winsound", "wsgiref", "xdrlib", "xml", "xmlrpc", "xx", "xxlimited", "xxsubtype", "zipapp", "zipfile", "zipimport", "zlib", "zoneinfo", } isort-6.0.1/rtd/index.md0000644000000000000000000000046413615410400012024 0ustar00 The latest isort docs are not on ReadTheDocs. This page contains a javascript redirect to the latest documentation. If this redirect doesn't work, please [click here for the latest documentation](https://pycqa.github.io/isort/). isort-6.0.1/scripts/build_config_option_docs.py0000755000000000000000000003222713615410400016674 0ustar00#! /bin/env python import dataclasses import os from textwrap import dedent from typing import Any, Dict, Generator, Iterable, Optional, Type from isort.main import _build_arg_parser from isort.settings import _DEFAULT_SETTINGS as config OUTPUT_FILE = os.path.abspath( os.path.join(os.path.dirname(os.path.abspath(__file__)), "../docs/configuration/options.md") ) MD_NEWLINE = " " HUMAN_NAME = { "py_version": "Python Version", "vn": "Version Number", "str": "String", "frozenset": "List of Strings", "tuple": "List of Strings", } CONFIG_DEFAULTS = {"False": "false", "True": "true", "None": ""} DESCRIPTIONS = {} IGNORED = {"source", "help", "sources", "directory"} COLUMNS = ["Name", "Type", "Default", "Python / Config file", "CLI", "Description"] HEADER = """# Configuration options for isort As a code formatter isort has opinions. However, it also allows you to have your own. If your opinions disagree with those of isort, isort will disagree but commit to your way of formatting. To enable this, isort exposes a plethora of options to specify how you want your imports sorted, organized, and formatted. Too busy to build your perfect isort configuration? For curated common configurations, see isort's [built-in profiles](https://pycqa.github.io/isort/docs/configuration/profiles.html). """ parser = _build_arg_parser() @dataclasses.dataclass class Example: section_complete: str = "" cfg: str = "" pyproject_toml: str = "" cli: str = "" def __post_init__(self): if self.cfg or self.pyproject_toml or self.cli: if self.cfg: cfg = dedent(self.cfg).lstrip() self.cfg = ( dedent( """ ### Example `.isort.cfg` ``` [settings] {cfg} ``` """ ) .format(cfg=cfg) .lstrip() ) if self.pyproject_toml: pyproject_toml = dedent(self.pyproject_toml).lstrip() self.pyproject_toml = ( dedent( """ ### Example `pyproject.toml` ``` [tool.isort] {pyproject_toml} ``` """ ) .format(pyproject_toml=pyproject_toml) .lstrip() ) if self.cli: cli = dedent(self.cli).lstrip() self.cli = ( dedent( """ ### Example cli usage `{cli}` """ ) .format(cli=cli) .lstrip() ) sections = [s for s in [self.cfg, self.pyproject_toml, self.cli] if s] sections_str = "\n".join(sections) self.section_complete = f"""**Examples:** {sections_str}""" else: self.section_complete = "" def __str__(self): return self.section_complete description_mapping: Dict[str, str] description_mapping = { "length_sort_sections": "Sort the given sections by length", "forced_separate": "Force certain sub modules to show separately", "sections": "What sections isort should display imports for and in what order", "known_other": "known_OTHER is how imports of custom sections are defined. " "OTHER is a placeholder for the custom section name.", "comment_prefix": "Allows customizing how isort prefixes comments that it adds or modifies on import lines" "Generally ` #` (two spaces before a pound symbol) is use, though one space is also common.", "lines_before_imports": "The number of blank lines to place before imports. -1 for automatic determination", "lines_after_imports": "The number of blank lines to place after imports. -1 for automatic determination", "lines_between_sections": "The number of lines to place between sections", "lines_between_types": "The number of lines to place between direct and from imports", "lexicographical": "Lexicographical order is strictly alphabetical order. " "For example by default isort will sort `1, 10, 2` into `1, 2, 10` - but with " "lexicographical sorting enabled it will remain `1, 10, 2`.", "ignore_comments": "If enabled, isort will strip comments that exist within import lines.", "constants": "An override list of tokens to always recognize as a CONSTANT for order_by_type regardless of casing.", "classes": "An override list of tokens to always recognize as a Class for order_by_type regardless of casing.", "variables": "An override list of tokens to always recognize as a var for order_by_type regardless of casing.", "auto_identify_namespace_packages": "Automatically determine local namespace packages, generally by lack of any src files before a src containing directory.", "namespace_packages": "Manually specify one or more namespace packages.", "follow_links": "If `True` isort will follow symbolic links when doing recursive sorting.", "git_ignore": "If `True` isort will honor ignores within locally defined .git_ignore files.", "formatting_function": "The fully qualified Python path of a function to apply to format code sorted by isort.", "group_by_package": "If `True` isort will automatically create section groups by the top-level package they come from.", "indented_import_headings": "If `True` isort will apply import headings to indented imports the same way it does unindented ones.", "import_headings": "A mapping of import sections to import heading comments that should show above them.", "import_footers": "A mapping of import sections to import footer comments that should show below them.", } example_mapping: Dict[str, Example] example_mapping = { "skip": Example( cfg=""" skip=.gitignore,.dockerignore""", pyproject_toml=""" skip = [".gitignore", ".dockerignore"] """, ), "extend_skip": Example( cfg=""" extend_skip=.md,.json""", pyproject_toml=""" extend_skip = [".md", ".json"] """, ), "skip_glob": Example( cfg=""" skip_glob=docs/* """, pyproject_toml=""" skip_glob = ["docs/*"] """, ), "extend_skip_glob": Example( cfg=""" extend_skip_glob=my_*_module.py,test/* """, pyproject_toml=""" extend_skip_glob = ["my_*_module.py", "test/*"] """, ), "known_third_party": Example( cfg=""" known_third_party=my_module1,my_module2 """, pyproject_toml=""" known_third_party = ["my_module1", "my_module2"] """, ), "known_first_party": Example( cfg=""" known_first_party=my_module1,my_module2 """, pyproject_toml=""" known_first_party = ["my_module1", "my_module2"] """, ), "known_local_folder": Example( cfg=""" known_local_folder=my_module1,my_module2 """, pyproject_toml=""" known_local_folder = ["my_module1", "my_module2"] """, ), "known_standard_library": Example( cfg=""" known_standard_library=my_module1,my_module2 """, pyproject_toml=""" known_standard_library = ["my_module1", "my_module2"] """, ), "extra_standard_library": Example( cfg=""" extra_standard_library=my_module1,my_module2 """, pyproject_toml=""" extra_standard_library = ["my_module1", "my_module2"] """, ), "forced_separate": Example( cfg=""" forced_separate=glob_exp1,glob_exp2 """, pyproject_toml=""" forced_separate = ["glob_exp1", "glob_exp2"] """, ), "length_sort_sections": Example( cfg=""" length_sort_sections=future,stdlib """, pyproject_toml=""" length_sort_sections = ["future", "stdlib"] """, ), "add_imports": Example( cfg=""" add_imports=import os,import json """, pyproject_toml=""" add_imports = ["import os", "import json"] """, ), "remove_imports": Example( cfg=""" remove_imports=os,json """, pyproject_toml=""" remove_imports = ["os", "json"] """, ), "single_line_exclusions": Example( cfg=""" single_line_exclusions=os,json """, pyproject_toml=""" single_line_exclusions = ["os", "json"] """, ), "no_lines_before": Example( cfg=""" no_lines_before=future,stdlib """, pyproject_toml=""" no_lines_before = ["future", "stdlib"] """, ), "src_paths": Example( cfg=""" src_paths = src,tests """, pyproject_toml=""" src_paths = ["src", "tests"] """, ), "treat_comments_as_code": Example( cfg=""" treat_comments_as_code = # my comment 1, # my other comment """, pyproject_toml=""" treat_comments_as_code = ["# my comment 1", "# my other comment"] """, ), "supported_extensions": Example( cfg=""" supported_extensions=pyw,ext """, pyproject_toml=""" supported_extensions = ["pyw", "ext"] """, ), "blocked_extensions": Example( cfg=""" blocked_extensions=pyw,pyc """, pyproject_toml=""" blocked_extensions = ["pyw", "pyc"] """, ), "known_other": Example( cfg=""" sections=FUTURE,STDLIB,THIRDPARTY,AIRFLOW,FIRSTPARTY,LOCALFOLDER known_airflow=airflow""", pyproject_toml=""" sections = ['FUTURE', 'STDLIB', 'THIRDPARTY', 'AIRFLOW', 'FIRSTPARTY', 'LOCALFOLDER'] known_airflow = ['airflow']""", ), "multi_line_output": Example(cfg="multi_line_output=3", pyproject_toml="multi_line_output = 3"), "show_version": Example(cli="isort --version"), "py_version": Example( cli="isort --py 39", pyproject_toml=""" py_version=39 """, cfg=""" py_version=39 """, ), } @dataclasses.dataclass class ConfigOption: name: str type: Type = str default: Any = "" config_name: str = "**Not Supported**" cli_options: Iterable[str] = (" **Not Supported**",) description: str = "**No Description**" example: Optional[Example] = None def __str__(self): if self.name in IGNORED: return "" if self.cli_options == (" **Not Supported**",): cli_options = self.cli_options[0] else: cli_options = "\n\n- " + "\n- ".join(self.cli_options) # new line if example otherwise nothing example = f"\n{self.example}" if self.example else "" return f""" ## {human(self.name)} {self.description} **Type:** {human(self.type.__name__)}{MD_NEWLINE} **Default:** `{str(self.default) or " "}`{MD_NEWLINE} **Config default:** `{config_default(self.default) or " "}`{MD_NEWLINE} **Python & Config File Name:** {self.config_name}{MD_NEWLINE} **CLI Flags:**{cli_options} {example}""" def config_default(default: Any) -> str: if isinstance(default, (frozenset, tuple)): default = list(default) default_str = str(default) if default_str in CONFIG_DEFAULTS: return CONFIG_DEFAULTS[default_str] if default_str.startswith("py"): return default_str[2:] return default_str def human(name: str) -> str: if name in HUMAN_NAME: return HUMAN_NAME[name] return " ".join( part if part in ("of",) else part.capitalize() for part in name.replace("-", "_").split("_") ) def config_options() -> Generator[ConfigOption, None, None]: cli_actions = {action.dest: action for action in parser._actions} for name, default in config.items(): extra_kwargs = {} description: Optional[str] = description_mapping.get(name, None) cli = cli_actions.pop(name, None) if cli: extra_kwargs["cli_options"] = cli.option_strings if cli.help and not description: description = cli.help default_display = default if isinstance(default, (set, frozenset)) and len(default) > 0: default_display = tuple(sorted(default)) # todo: refactor place for example params # needs to integrate with isort/settings/_Config # needs to integrate with isort/main/_build_arg_parser yield ConfigOption( name=name, type=type(default), default=default_display, config_name=name, description=description or "**No Description**", example=example_mapping.get(name, None), **extra_kwargs, ) for name, cli in cli_actions.items(): extra_kwargs = {} description: Optional[str] = description_mapping.get(name, None) if cli.type: extra_kwargs["type"] = cli.type elif cli.default is not None: extra_kwargs["type"] = type(cli.default) if cli.help and not description: description = cli.help yield ConfigOption( name=name, default=cli.default, cli_options=cli.option_strings, example=example_mapping.get(name, None), description=description or "**No Description**", **extra_kwargs, ) def document_text() -> str: return f"{HEADER}{''.join(str(config_option) for config_option in config_options())}" def write_document(): with open(OUTPUT_FILE, "w") as output_file: output_file.write(document_text()) if __name__ == "__main__": write_document() isort-6.0.1/scripts/build_profile_docs.py0000755000000000000000000000211313615410400015466 0ustar00#! /bin/env python import os from typing import Any, Dict from isort.profiles import profiles OUTPUT_FILE = os.path.abspath( os.path.join(os.path.dirname(os.path.abspath(__file__)), "../docs/configuration/profiles.md") ) HEADER = """Built-in Profile for isort ======== The following profiles are built into isort to allow easy interoperability with common projects and code styles. To use any of the listed profiles, use `isort --profile PROFILE_NAME` from the command line, or `profile=PROFILE_NAME` in your configuration file. """ def format_profile(profile_name: str, profile: Dict[str, Any]) -> str: options = "\n".join(f" - **{name}**: `{value!r}`" for name, value in profile.items()) return f""" #{profile_name} {profile.get('description', '')} {options} """ def document_text() -> str: return f"{HEADER}{''.join(format_profile(profile_name, profile) for profile_name, profile in profiles.items())}" def write_document(): with open(OUTPUT_FILE, "w") as output_file: output_file.write(document_text()) if __name__ == "__main__": write_document() isort-6.0.1/scripts/check_acknowledgments.py0000755000000000000000000000465013615410400016171 0ustar00#!/usr/bin/env python3 import asyncio import sys from getpass import getpass from pathlib import Path from typing import Dict import httpx import hug IGNORED_AUTHOR_LOGINS = {"deepsource-autofix[bot]"} REPO = "pycqa/isort" GITHUB_API_CONTRIBUTORS = f"https://api.github.com/repos/{REPO}/contributors" GITHUB_USER_CONTRIBUTIONS = f"https://github.com/{REPO}/commits?author=" GITHUB_USER_TYPE = "User" USER_DELIMITER = "-" * 80 PER_PAGE = 100 _ACK_FILE = Path(__file__).parent.parent / "docs" / "contributing" / "4.-acknowledgements.md" ACKNOWLEDGEMENTS = _ACK_FILE.read_text().lower() def _user_info(user: Dict[str, str], verbose=False) -> str: login = "@" + user["login"] name = user.get("name") display_name = f"{name} ({login})" if name else login user_info = f"- {display_name}" if verbose: contributions = f" {GITHUB_USER_CONTRIBUTIONS}{user['login']}" user_info += "\n" + contributions return user_info @hug.cli() async def main(): auth = (input("Github Username: "), getpass()) async with httpx.AsyncClient() as client: page = 0 results = [] contributors = [] while not page or len(results) == PER_PAGE: page += 1 response = await client.get( f"{GITHUB_API_CONTRIBUTORS}?per_page={PER_PAGE}&page={page}", auth=auth ) results = response.json() contributors.extend( contributor for contributor in results if contributor["type"] == GITHUB_USER_TYPE and contributor["login"] not in IGNORED_AUTHOR_LOGINS and f"@{contributor['login'].lower()}" not in ACKNOWLEDGEMENTS ) unacknowledged_users = await asyncio.gather( *(client.get(contributor["url"], auth=auth) for contributor in contributors) ) unacknowledged_users = [request.json() for request in unacknowledged_users] if not unacknowledged_users: sys.exit() print("Found unacknowledged authors:") print() for user in unacknowledged_users: print(_user_info(user, verbose=True)) print(USER_DELIMITER) print() print("Printing again for easy inclusion in Markdown file:") print() for user in unacknowledged_users: print(_user_info(user)) sys.exit(1) if __name__ == "__main__": main.interface.cli() isort-6.0.1/scripts/clean.sh0000755000000000000000000000026413615410400012710 0ustar00#!/bin/bash set -euxo pipefail uv run isort --profile hug isort/ tests/ scripts/ uv run isort --profile hug example_*/ uv run black isort/ tests/ scripts/ uv run black example_*/ isort-6.0.1/scripts/docker.sh0000755000000000000000000000045313615410400013075 0ustar00#!/bin/bash set -ux result=0 for ver in {3.9,3.10}; do # latest tag will override after each build, leaving only the newest python version tagged docker build ./ --build-arg VERSION=$ver -t "isort:$ver" -t "isort:latest" && docker run "isort:$ver" result=$(( $? + $result )) done exit $result isort-6.0.1/scripts/done.sh0000755000000000000000000000010513615410400012545 0ustar00#!/bin/bash set -euxo pipefail ./scripts/clean.sh ./scripts/test.sh isort-6.0.1/scripts/lint.sh0000755000000000000000000000053413615410400012574 0ustar00#!/bin/bash set -euxo pipefail uv run cruft check uv run mypy -p isort -p tests uv run black --target-version py39 --check . uv run isort --profile hug --check --diff isort/ tests/ uv run isort --profile hug --check --diff example_*/ uv run --with=Flake8-pyproject flake8 isort/ tests/ uv run ruff check uv run bandit -r isort/ -x isort/_vendored isort-6.0.1/scripts/mkstdlibs.py0000755000000000000000000000306413615410400013641 0ustar00#!/usr/bin/env python3 import re from stdlibs import py38, py39, py310, py311, py312, py313 URL = "https://docs.python.org/{}/objects.inv" PATH = "isort/stdlibs/py{}.py" VERSIONS = [ py38, py39, py310, py311, py312, py313, ] DOCSTRING = """ File contains the standard library of Python {}. DO NOT EDIT. If the standard library changes, a new list should be created using the mkstdlibs.py script. """ class FakeConfig: intersphinx_timeout = None tls_verify = True user_agent = "" tls_cacerts = None class FakeApp: srcdir = "" config = FakeConfig() for version_module in VERSIONS: version_match = re.match( r"^stdlibs\.py(?P\d)(?P\d+)$", version_module.__name__, ) version_info = (version_match.groupdict()["major"], version_match.groupdict()["minor"]) # Any modules we want to enforce across Python versions stdlib can be included in set init modules = {"_ast", "posixpath", "ntpath", "sre_constants", "sre_parse", "sre_compile", "sre"} modules.update( { module_name for module_name in version_module.module_names if not module_name.startswith("_") } ) path = PATH.format("".join(version_info)) with open(path, "w") as stdlib_file: docstring = DOCSTRING.format(".".join(version_info)) stdlib_file.write(f'"""{docstring}"""\n\n') stdlib_file.write("stdlib = {\n") for module in sorted(modules): stdlib_file.write(f' "{module}",\n') stdlib_file.write("}\n") isort-6.0.1/scripts/test.sh0000755000000000000000000000031213615410400012577 0ustar00#!/bin/bash set -euxo pipefail uv run coverage run --parallel -m pytest tests/unit/ -s --ignore=tests/unit/test_deprecated_finders.py uv run coverage combine uv run coverage report uv run coverage xml isort-6.0.1/scripts/test_integration.sh0000755000000000000000000000010413615410400015201 0ustar00#!/bin/bash set -euxo pipefail uv run pytest tests/integration/ -s isort-6.0.1/tests/__init__.py0000644000000000000000000000000013615410400013037 0ustar00isort-6.0.1/tests/benchmark/test_api.py0000644000000000000000000000143113615410400015053 0ustar00from typing import Any import pytest from isort import api imperfect_content = "import b\nimport a\n" fixed_content = "import a\nimport b\n" @pytest.fixture def imperfect(tmpdir) -> Any: imperfect_file = tmpdir.join("test_needs_changes.py") imperfect_file.write_text(imperfect_content, "utf8") return imperfect_file def test_sort_file(benchmark, imperfect) -> None: def sort_file(): api.sort_file(imperfect) benchmark.pedantic(sort_file, iterations=10, rounds=100) assert imperfect.read() == fixed_content def test_sort_file_in_place(benchmark, imperfect) -> None: def sort_file(): api.sort_file(imperfect, overwrite_in_place=True) benchmark.pedantic(sort_file, iterations=10, rounds=100) assert imperfect.read() == fixed_content isort-6.0.1/tests/integration/test_hypothesmith.py0000644000000000000000000000670613615410400017432 0ustar00import ast from typing import get_type_hints import hypothesis import libcst from hypothesis import strategies as st from hypothesmith import from_grammar, from_node import isort def _as_config(kw) -> isort.Config: if "wrap_length" in kw and "line_length" in kw: kw["wrap_length"], kw["line_length"] = sorted([kw["wrap_length"], kw["line_length"]]) try: return isort.Config(**kw) except ValueError: kw["wrap_length"] = 0 return isort.Config(**kw) def _record_targets(code: str, prefix: str = "") -> str: # target larger inputs - the Hypothesis engine will do a multi-objective # hill-climbing search using these scores to generate 'better' examples. nodes = list(ast.walk(ast.parse(code))) import_nodes = [n for n in nodes if isinstance(n, (ast.Import, ast.ImportFrom))] uniq_nodes = {type(n) for n in nodes} for value, label in [ (len(import_nodes), "total number of import nodes"), (len(uniq_nodes), "number of unique ast node types"), ]: hypothesis.target(float(value), label=prefix + label) return code def configs(**force_strategies: st.SearchStrategy) -> st.SearchStrategy: """Generate arbitrary Config objects.""" skip = { "line_ending", "sections", "known_future_library", "forced_separate", "lines_before_imports", "lines_after_imports", "lines_between_sections", "lines_between_types", "sources", "virtual_env", "conda_env", "directory", "formatter", "formatting_function", } inferred_kwargs = { k: st.from_type(v) for k, v in get_type_hints(isort.settings._Config).items() if k not in skip } specific = { "line_length": st.integers(0, 200), "wrap_length": st.integers(0, 200), "indent": st.integers(0, 20).map(lambda n: n * " "), "default_section": st.sampled_from(sorted(isort.settings.KNOWN_SECTION_MAPPING)), "force_grid_wrap": st.integers(0, 20), "profile": st.sampled_from(sorted(isort.settings.profiles)), "py_version": st.sampled_from(("auto", *isort.settings.VALID_PY_TARGETS)), } kwargs = {**inferred_kwargs, **specific, **force_strategies} return st.fixed_dictionaries({}, optional=kwargs).map(_as_config) st.register_type_strategy(isort.Config, configs()) @hypothesis.example("import A\nimportA\r\n\n", isort.Config(), False) @hypothesis.given( source_code=st.lists( from_grammar(auto_target=False) | from_node(auto_target=False) | from_node(libcst.Import, auto_target=False) | from_node(libcst.ImportFrom, auto_target=False), min_size=1, max_size=10, ).map("\n".join), config=st.builds(isort.Config), disregard_skip=st.booleans(), ) @hypothesis.seed(235738473415671197623909623354096762459) @hypothesis.settings( suppress_health_check=[hypothesis.HealthCheck.too_slow, hypothesis.HealthCheck.filter_too_much] ) def test_isort_is_idempotent(source_code: str, config: isort.Config, disregard_skip: bool) -> None: # NOTE: if this test finds a bug, please notify @Zac-HD so that it can be added to the # Hypothesmith trophy case. This really helps with research impact evaluations! _record_targets(source_code) result = isort.code(source_code, config=config, disregard_skip=disregard_skip) assert result == isort.code(result, config=config, disregard_skip=disregard_skip) isort-6.0.1/tests/integration/test_literal.py0000644000000000000000000000072413615410400016333 0ustar00"""Tests that need installation of other packages.""" # TODO: find a way to install example-isort-formatting-plugin to pass tests # import isort.literal # from isort.settings import Config # def test_value_assignment_list(): # assert isort.literal.assignment("x = ['b', 'a']", "list", "py") == "x = ['a', 'b']" # assert ( # isort.literal.assignment("x = ['b', 'a']", "list", "py", Config(formatter="example")) # == 'x = ["a", "b"]' # ) isort-6.0.1/tests/integration/test_projects_using_isort.py0000644000000000000000000000604313615410400021155 0ustar00"""Tests projects that use isort to see if any differences are found between their current imports and what isort suggest on the develop branch. This is an important early warning signal of regressions. NOTE: If you use isort within a public repository, please feel empowered to add your project here! It is important to isort that as few regressions as possible are experienced by our users. Having your project tested here is the most sure way to keep those regressions form ever happening. """ from __future__ import annotations from pathlib import Path from subprocess import check_call from typing import Generator, Sequence import pytest from isort.main import main def git_clone(repository_url: str, directory: Path): """Clones the given repository into the given directory path""" check_call(["git", "clone", "--depth", "1", repository_url, str(directory)]) def run_isort(arguments: Generator[str, None, None] | Sequence[str]): """Runs isort in diff and check mode with the given arguments""" main(["--check-only", "--diff", *arguments]) @pytest.mark.xfail( reason="Project is incorrectly formatted after PR #2236, should be fixed " "after a release and the project formatting again." ) def test_django(tmpdir): git_clone("https://github.com/django/django.git", tmpdir) run_isort( str(target_dir) for target_dir in (tmpdir / "django", tmpdir / "tests", tmpdir / "scripts") ) def test_plone(tmpdir): git_clone("https://github.com/plone/plone.app.multilingualindexes.git", tmpdir) run_isort([str(tmpdir / "src"), "--skip", "languagefallback.py"]) def test_pandas(tmpdir): git_clone("https://github.com/pandas-dev/pandas.git", tmpdir) run_isort((str(tmpdir / "pandas"), "--skip", "__init__.py")) def test_habitat_lab(tmpdir): git_clone("https://github.com/facebookresearch/habitat-lab.git", tmpdir) run_isort([str(tmpdir)]) def test_pylint(tmpdir): git_clone("https://github.com/PyCQA/pylint.git", tmpdir) run_isort([str(tmpdir), "--skip", "bad.py"]) def test_hypothesis(tmpdir): git_clone("https://github.com/HypothesisWorks/hypothesis.git", tmpdir) run_isort( ( str(tmpdir), "--skip", "tests", "--profile", "black", "--ca", "--project", "hypothesis", "--project", "hypothesistooling", ) ) def test_pyramid(tmpdir): git_clone("https://github.com/Pylons/pyramid.git", tmpdir) run_isort( str(target_dir) for target_dir in (tmpdir / "src" / "pyramid", tmpdir / "tests", tmpdir / "setup.py") ) def test_products_zopetree(tmpdir): git_clone("https://github.com/jugmac00/Products.ZopeTree.git", tmpdir) run_isort([str(tmpdir)]) def test_dobby(tmpdir): git_clone("https://github.com/rocketDuck/dobby.git", tmpdir) run_isort([str(tmpdir / "tests"), str(tmpdir / "src")]) def test_zope(tmpdir): git_clone("https://github.com/zopefoundation/Zope.git", tmpdir) run_isort([str(tmpdir), "--skip", "util.py"]) isort-6.0.1/tests/integration/test_setting_combinations.py0000644000000000000000000016534313615410400021132 0ustar00from typing import get_type_hints import hypothesis from hypothesis import strategies as st import isort def _as_config(kw) -> isort.Config: kw["atomic"] = False if "wrap_length" in kw and "line_length" in kw: kw["wrap_length"], kw["line_length"] = sorted([kw["wrap_length"], kw["line_length"]]) try: return isort.Config(**kw) except ValueError: kw["wrap_length"] = 0 return isort.Config(**kw) def configs() -> st.SearchStrategy: """Generate arbitrary Config objects.""" skip = { "line_ending", "sections", "known_standard_library", "known_future_library", "known_third_party", "known_first_party", "known_local_folder", "extra_standard_library", "forced_separate", "lines_before_imports", "lines_after_imports", "add_imports", "lines_between_sections", "lines_between_types", "sources", "virtual_env", "conda_env", "directory", "formatter", "formatting_function", "comment_prefix", "atomic", "skip", "src_paths", } inferred_kwargs = { k: st.from_type(v) for k, v in get_type_hints(isort.settings._Config).items() if k not in skip } specific = { "line_length": st.integers(0, 200), "wrap_length": st.integers(0, 200), "indent": st.integers(0, 20).map(lambda n: n * " "), "default_section": st.sampled_from(sorted(isort.settings.KNOWN_SECTION_MAPPING)), "force_grid_wrap": st.integers(0, 20), "profile": st.sampled_from(sorted(isort.settings.profiles)), "sort_order": st.sampled_from(sorted(("native", "natural", "natural_plus"))), "py_version": st.sampled_from(("auto", *isort.settings.VALID_PY_TARGETS)), } kwargs = {**inferred_kwargs, **specific} return st.fixed_dictionaries({}, optional=kwargs).map(_as_config) st.register_type_strategy(isort.Config, configs()) CODE_SNIPPET = """ '''Taken from bottle.py Copyright (c) 2009-2018, Marcel Hellkamp. License: MIT (see LICENSE for details) ''' # Lots of stdlib and builtin differences. if py3k: import http.client as httplib import _thread as thread from urllib.parse import urljoin, SplitResult as UrlSplitResult from urllib.parse import urlencode, quote as urlquote, unquote as urlunquote urlunquote = functools.partial(urlunquote, encoding='latin1') from http.cookies import SimpleCookie, Morsel, CookieError from collections.abc import MutableMapping as DictMixin import pickle # comment number 2 from io import BytesIO import configparser basestring = str unicode = str json_loads = lambda s: json_lds(touni(s)) callable = lambda x: hasattr(x, '__call__') imap = map def _raise(*a): raise a[0](a[1]).with_traceback(a[2]) else: # 2.x import httplib import thread from urlparse import urljoin, SplitResult as UrlSplitResult from urllib import urlencode, quote as urlquote, unquote as urlunquote from Cookie import SimpleCookie, Morsel, CookieError from itertools import imap import cPickle as pickle from StringIO import StringIO as BytesIO import ConfigParser as configparser # commentnumberone from collections import MutableMapping as DictMixin unicode = unicode json_loads = json_lds exec(compile('def _raise(*a): raise a[0], a[1], a[2]', '', 'exec')) """ SHOULD_RETAIN = [ """'''Taken from bottle.py Copyright (c) 2009-2018, Marcel Hellkamp. License: MIT (see LICENSE for details) '''""", "# Lots of stdlib and builtin differences.", "if py3k:", "http.client", "_thread", "urllib.parse", "urlencode", "urlunquote = functools.partial(urlunquote, encoding='latin1')", "http.cookies", "SimpleCookie", "collections.abc", "pickle", "comment number 2", "io", "configparser", """basestring = str unicode = str json_loads = lambda s: json_lds(touni(s)) callable = lambda x: hasattr(x, '__call__') imap = map def _raise(*a): raise a[0](a[1]).with_traceback(a[2]) else: # 2.x """, "httplib", "thread", "urlparse", "urllib", "Cookie", "itertools", "cPickle", "StringIO", "ConfigParser", "commentnumberone", "collections", """unicode = unicode json_loads = json_lds exec(compile('def _raise(*a): raise a[0], a[1], a[2]', '', 'exec'))""", ] @hypothesis.example( config=isort.Config( py_version="all", force_to_top=frozenset(), skip=frozenset( { ".svn", ".venv", "build", "dist", ".bzr", ".tox", ".hg", ".mypy_cache", ".nox", "_build", "buck-out", "node_modules", ".git", ".eggs", ".pants.d", "venv", ".direnv", } ), skip_glob=frozenset(), skip_gitignore=True, line_length=79, wrap_length=0, line_ending="", sections=("FUTURE", "STDLIB", "THIRDPARTY", "FIRSTPARTY", "LOCALFOLDER"), no_sections=False, known_future_library=frozenset({"__future__"}), known_third_party=frozenset(), known_first_party=frozenset(), known_local_folder=frozenset(), known_standard_library=frozenset( { "pwd", "types", "nntplib", "jpeg", "pyclbr", "encodings", "ctypes", "macerrors", "filecmp", "dbm", "mimetypes", "statvfs", "msvcrt", "spwd", "codecs", "SimpleHTTPServer", "compiler", "pickletools", "tkinter", "pickle", "fm", "bsddb", "contextvars", "dummy_thread", "pipes", "heapq", "dircache", "commands", "unicodedata", "ntpath", "marshal", "fpformat", "linecache", "calendar", "pty", "MimeWriter", "inspect", "mmap", "ic", "tty", "nis", "new", "wave", "HTMLParser", "anydbm", "tracemalloc", "pdb", "sunau", "GL", "parser", "winsound", "dbhash", "zlib", "MacOS", "pprint", "crypt", "aetools", "DEVICE", "fl", "gettext", "asyncore", "copyreg", "queue", "resource", "turtledemo", "fnmatch", "hotshot", "trace", "string", "plistlib", "gzip", "functools", "aepack", "hashlib", "imp", "MiniAEFrame", "getpass", "shutil", "ttk", "multifile", "operator", "reprlib", "subprocess", "cgi", "select", "SimpleXMLRPCServer", "audioop", "macresource", "stringprep", "wsgiref", "SUNAUDIODEV", "atexit", "lzma", "asyncio", "datetime", "binhex", "autoGIL", "doctest", "thread", "enum", "tempfile", "posixfile", "mhlib", "html", "itertools", "exceptions", "sgmllib", "array", "test", "imputil", "shlex", "flp", "uu", "gdbm", "urlparse", "msilib", "termios", "modulefinder", "ossaudiodev", "timeit", "binascii", "popen2", "ConfigParser", "poplib", "zipfile", "cfmfile", "pstats", "AL", "contextlib", "code", "zipimport", "base64", "platform", "ast", "fileinput", "locale", "buildtools", "stat", "quopri", "readline", "collections", "aetypes", "concurrent", "runpy", "copy_reg", "rexec", "cmath", "optparse", "dummy_threading", "ColorPicker", "sched", "netrc", "sunaudiodev", "socketserver", "logging", "PixMapWrapper", "sysconfig", "Nav", "copy", "cmd", "csv", "chunk", "multiprocessing", "warnings", "weakref", "py_compile", "sre", "sre_parse", "curses", "threading", "re", "FrameWork", "_thread", "imgfile", "cd", "sre_constants", "xdrlib", "dataclasses", "urllib2", "StringIO", "configparser", "importlib", "UserList", "posixpath", "mailbox", "rfc822", "grp", "pydoc", "sets", "textwrap", "numbers", "W", "gl", "htmllib", "macostools", "tarfile", "ipaddress", "xmlrpc", "icopen", "traceback", "_winreg", "random", "CGIHTTPServer", "dis", "sha", "selectors", "statistics", "DocXMLRPCServer", "imghdr", "venv", "keyword", "xmlrpclib", "ftplib", "getopt", "posix", "smtpd", "profile", "sndhdr", "signal", "EasyDialogs", "dumbdbm", "fcntl", "SocketServer", "distutils", "symbol", "pathlib", "cStringIO", "imaplib", "unittest", "al", "cProfile", "robotparser", "BaseHTTPServer", "os", "pkgutil", "socket", "fractions", "shelve", "aifc", "cgitb", "xml", "decimal", "sre_compile", "ssl", "user", "Bastion", "formatter", "time", "abc", "winreg", "difflib", "FL", "bz2", "asynchat", "gc", "gensuitemodule", "symtable", "secrets", "Carbon", "mailcap", "sys", "bdb", "fpectl", "httplib", "webbrowser", "smtplib", "Cookie", "whichdb", "turtle", "tokenize", "UserString", "tabnanny", "site", "struct", "codeop", "email", "typing", "cookielib", "Queue", "rlcompleter", "errno", "macpath", "videoreader", "md5", "cPickle", "Tix", "io", "faulthandler", "Tkinter", "glob", "syslog", "telnetlib", "_dummy_thread", "hmac", "uuid", "imageop", "future_builtins", "json", "htmlentitydefs", "lib2to3", "UserDict", "mutex", "sqlite3", "findertools", "bisect", "builtins", "urllib", "http", "compileall", "argparse", "ScrolledText", "token", "dl", "applesingle", "math", "ensurepip", "mimify", "mimetools", "colorsys", "zipapp", "__builtin__", } ), extra_standard_library=frozenset(), known_other={"other": frozenset({"", "\x10\x1bm"})}, multi_line_output=0, forced_separate=(), indent=" ", comment_prefix=" #", length_sort=True, length_sort_straight=False, length_sort_sections=frozenset(), add_imports=frozenset(), remove_imports=frozenset( { "", "\U00076fe7þs\x0c\U000c8b75v\U00106541", "𥒒>\U0001960euj𒎕\x9e", "\x15\x9b", "\x02l", "\U000b71ef.\x1c", "\x7f?\U000ec91c", "\x7f,ÞoÀP8\x1b\x1e»3\x86\x94¤ÁÓ~\U00066b1a,O\U0010ab28\x90«", "Y\x06ºZ\x04Ýì\U00078ce1.\U0010c1f9[EK\x83EÖø", ";À¨|\x1b 𑐒🍸V", } ), append_only=False, reverse_relative=True, force_single_line=False, single_line_exclusions=( "Y\U000347d9g\x957K", "", "Ê\U000e8ad2\U0008fa72ùÏ\x19ç\U000eaecc𤎪.", "·o\U000d00e5\U000b36de+\x8f\U000b5953´\x08oÜ", "", ":sI¶", "", ), default_section="THIRDPARTY", import_headings={}, import_footers={}, balanced_wrapping=False, use_parentheses=True, order_by_type=True, atomic=False, lines_before_imports=-1, lines_after_imports=-1, lines_between_sections=1, lines_between_types=0, combine_as_imports=True, combine_star=False, include_trailing_comma=False, from_first=False, verbose=False, quiet=False, force_adds=False, force_alphabetical_sort_within_sections=False, force_alphabetical_sort=False, force_grid_wrap=0, force_sort_within_sections=False, lexicographical=False, ignore_whitespace=False, no_lines_before=frozenset( { "uøø", "¢", "&\x8c5Ï\U000e5f01Ø", "\U0005d415\U000a3df2h\U000f24e5\U00104d7b34¹ÒÀ", "\U000e374c8", "w", } ), no_inline_sort=False, ignore_comments=False, case_sensitive=False, sources=( { "py_version": "py3", "force_to_top": frozenset(), "skip": frozenset( { ".svn", ".venv", "build", "dist", ".bzr", ".tox", ".hg", ".mypy_cache", ".nox", "_build", "buck-out", "node_modules", ".git", ".eggs", ".pants.d", "venv", ".direnv", } ), "skip_glob": frozenset(), "skip_gitignore": False, "line_length": 79, "wrap_length": 0, "line_ending": "", "sections": ("FUTURE", "STDLIB", "THIRDPARTY", "FIRSTPARTY", "LOCALFOLDER"), "no_sections": False, "known_future_library": frozenset({"__future__"}), "known_third_party": frozenset(), "known_first_party": frozenset(), "known_local_folder": frozenset(), "known_standard_library": frozenset( { "pwd", "copy", "cmd", "csv", "chunk", "multiprocessing", "warnings", "types", "weakref", "nntplib", "pyclbr", "encodings", "py_compile", "sre", "ctypes", "sre_parse", "filecmp", "curses", "threading", "dbm", "re", "_thread", "sre_constants", "xdrlib", "dataclasses", "mimetypes", "configparser", "importlib", "msvcrt", "spwd", "posixpath", "mailbox", "codecs", "grp", "pickletools", "tkinter", "pickle", "contextvars", "pydoc", "textwrap", "numbers", "pipes", "heapq", "tarfile", "unicodedata", "ntpath", "ipaddress", "marshal", "xmlrpc", "traceback", "linecache", "calendar", "pty", "random", "dis", "selectors", "statistics", "imghdr", "venv", "inspect", "mmap", "keyword", "ftplib", "tty", "nis", "getopt", "posix", "smtpd", "wave", "profile", "sndhdr", "signal", "tracemalloc", "pdb", "sunau", "winsound", "parser", "zlib", "fcntl", "pprint", "distutils", "crypt", "symbol", "gettext", "pathlib", "asyncore", "copyreg", "imaplib", "unittest", "queue", "resource", "turtledemo", "fnmatch", "cProfile", "os", "pkgutil", "socket", "trace", "fractions", "string", "shelve", "plistlib", "aifc", "gzip", "functools", "cgitb", "xml", "hashlib", "decimal", "imp", "sre_compile", "ssl", "formatter", "winreg", "time", "getpass", "shutil", "abc", "difflib", "bz2", "operator", "reprlib", "subprocess", "cgi", "select", "asynchat", "audioop", "gc", "secrets", "symtable", "mailcap", "sys", "bdb", "fpectl", "stringprep", "webbrowser", "smtplib", "wsgiref", "atexit", "lzma", "asyncio", "datetime", "binhex", "doctest", "turtle", "enum", "tempfile", "tokenize", "tabnanny", "site", "html", "struct", "itertools", "codeop", "email", "array", "test", "typing", "shlex", "uu", "msilib", "termios", "rlcompleter", "modulefinder", "ossaudiodev", "timeit", "binascii", "poplib", "errno", "macpath", "zipfile", "io", "faulthandler", "pstats", "contextlib", "code", "glob", "zipimport", "base64", "syslog", "platform", "ast", "fileinput", "telnetlib", "locale", "_dummy_thread", "hmac", "stat", "uuid", "quopri", "readline", "collections", "json", "concurrent", "lib2to3", "sqlite3", "runpy", "cmath", "optparse", "bisect", "builtins", "urllib", "dummy_threading", "http", "compileall", "argparse", "token", "sched", "netrc", "math", "ensurepip", "socketserver", "colorsys", "zipapp", "logging", "sysconfig", } ), "extra_standard_library": frozenset(), "known_other": {}, "multi_line_output": 0, "forced_separate": (), "indent": " ", "comment_prefix": " #", "length_sort": False, "length_sort_straight": False, "length_sort_sections": frozenset(), "add_imports": frozenset(), "remove_imports": frozenset(), "append_only": False, "reverse_relative": False, "force_single_line": False, "single_line_exclusions": (), "default_section": "THIRDPARTY", "import_headings": {}, "import_footers": {}, "balanced_wrapping": False, "use_parentheses": False, "order_by_type": True, "atomic": False, "lines_before_imports": -1, "lines_after_imports": -1, "lines_between_sections": 1, "lines_between_types": 0, "combine_as_imports": False, "combine_star": False, "include_trailing_comma": False, "from_first": False, "verbose": False, "quiet": False, "force_adds": False, "force_alphabetical_sort_within_sections": False, "force_alphabetical_sort": False, "force_grid_wrap": 0, "force_sort_within_sections": False, "lexicographical": False, "ignore_whitespace": False, "no_lines_before": frozenset(), "no_inline_sort": False, "ignore_comments": False, "case_sensitive": False, "sources": (), "virtual_env": "", "conda_env": "", "ensure_newline_before_comments": False, "directory": "", "profile": "", "honor_noqa": False, "src_paths": frozenset(), "old_finders": False, "remove_redundant_aliases": False, "float_to_top": False, "filter_files": False, "formatter": "", "formatting_function": None, "color_output": False, "treat_comments_as_code": frozenset(), "treat_all_comments_as_code": False, "supported_extensions": frozenset({"py", "pyx", "pyi"}), "blocked_extensions": frozenset({"pex"}), "constants": frozenset(), "classes": frozenset(), "variables": frozenset(), "dedup_headings": False, "source": "defaults", }, { "classes": frozenset( { "\U000eb6c6\x9eÑ\U0008297dâhï\x8eÆ", "C", "\x8e\U000422ac±\U000b5a1f\U000c4166", "ùÚ", } ), "single_line_exclusions": ( "Y\U000347d9g\x957K", "", "Ê\U000e8ad2\U0008fa72ùÏ\x19ç\U000eaecc𤎪.", "·o\U000d00e5\U000b36de+\x8f\U000b5953´\x08oÜ", "", ":sI¶", "", ), "indent": " ", "no_lines_before": frozenset( { "uøø", "¢", "&\x8c5Ï\U000e5f01Ø", "\U0005d415\U000a3df2h\U000f24e5\U00104d7b34¹ÒÀ", "\U000e374c8", "w", } ), "quiet": False, "honor_noqa": False, "dedup_headings": True, "known_other": { "\x10\x1bm": frozenset({"\U000682a49\U000e1a63²KǶ4", "", "\x1a", "©"}), "": frozenset({"íå\x94Ì", "\U000cf258"}), }, "treat_comments_as_code": frozenset({""}), "length_sort": True, "reverse_relative": True, "combine_as_imports": True, "py_version": "all", "use_parentheses": True, "skip_gitignore": True, "remove_imports": frozenset( { "", "\U00076fe7þs\x0c\U000c8b75v\U00106541", "𥒒>\U0001960euj𒎕\x9e", "\x15\x9b", "\x02l", "\U000b71ef.\x1c", "\x7f?\U000ec91c", "\x7f,ÞoÀP8\x1b\x1e»3\x86\x94¤ÁÓ~\U00066b1a,O\U0010ab28\x90«", "Y\x06ºZ\x04Ýì\U00078ce1.\U0010c1f9[EK\x83EÖø", ";À¨|\x1b 𑐒🍸V", } ), "atomic": False, "source": "runtime", }, ), virtual_env="", conda_env="", ensure_newline_before_comments=False, directory="/home/abuild/rpmbuild/BUILD/isort-5.11.0", profile="", honor_noqa=False, old_finders=False, remove_redundant_aliases=False, float_to_top=False, filter_files=False, formatting_function=None, color_output=False, treat_comments_as_code=frozenset({""}), treat_all_comments_as_code=False, supported_extensions=frozenset({"py", "pyx", "pyi"}), blocked_extensions=frozenset({"pex"}), constants=frozenset(), classes=frozenset( {"\U000eb6c6\x9eÑ\U0008297dâhï\x8eÆ", "C", "\x8e\U000422ac±\U000b5a1f\U000c4166", "ùÚ"} ), variables=frozenset(), dedup_headings=True, ), disregard_skip=True, ) @hypothesis.example( config=isort.Config( py_version="2", combine_straight_imports=True, ), disregard_skip=True, ) @hypothesis.given( config=st.from_type(isort.Config), disregard_skip=st.booleans(), ) @hypothesis.settings(deadline=None) def test_isort_is_idempotent(config: isort.Config, disregard_skip: bool) -> None: try: result = isort.code(CODE_SNIPPET, config=config, disregard_skip=disregard_skip) result = isort.code(result, config=config, disregard_skip=disregard_skip) assert result == isort.code(result, config=config, disregard_skip=disregard_skip) except ValueError: pass @hypothesis.example( config=isort.Config( py_version="all", force_to_top=frozenset(), skip=frozenset( { ".svn", ".venv", "build", "dist", ".bzr", ".tox", ".hg", ".mypy_cache", ".nox", "_build", "buck-out", "node_modules", ".git", ".eggs", ".pants.d", "venv", ".direnv", } ), skip_glob=frozenset(), skip_gitignore=True, line_length=79, wrap_length=0, line_ending="", sections=("FUTURE", "STDLIB", "THIRDPARTY", "FIRSTPARTY", "LOCALFOLDER"), no_sections=False, known_future_library=frozenset({"__future__"}), known_third_party=frozenset(), known_first_party=frozenset(), known_local_folder=frozenset(), known_standard_library=frozenset( { "pwd", "types", "nntplib", "jpeg", "pyclbr", "encodings", "ctypes", "macerrors", "filecmp", "dbm", "mimetypes", "statvfs", "msvcrt", "spwd", "codecs", "SimpleHTTPServer", "compiler", "pickletools", "tkinter", "pickle", "fm", "bsddb", "contextvars", "dummy_thread", "pipes", "heapq", "dircache", "commands", "unicodedata", "ntpath", "marshal", "fpformat", "linecache", "calendar", "pty", "MimeWriter", "inspect", "mmap", "ic", "tty", "nis", "new", "wave", "HTMLParser", "anydbm", "tracemalloc", "pdb", "sunau", "GL", "parser", "winsound", "dbhash", "zlib", "MacOS", "pprint", "crypt", "aetools", "DEVICE", "fl", "gettext", "asyncore", "copyreg", "queue", "resource", "turtledemo", "fnmatch", "hotshot", "trace", "string", "plistlib", "gzip", "functools", "aepack", "hashlib", "imp", "MiniAEFrame", "getpass", "shutil", "ttk", "multifile", "operator", "reprlib", "subprocess", "cgi", "select", "SimpleXMLRPCServer", "audioop", "macresource", "stringprep", "wsgiref", "SUNAUDIODEV", "atexit", "lzma", "asyncio", "datetime", "binhex", "autoGIL", "doctest", "thread", "enum", "tempfile", "posixfile", "mhlib", "html", "itertools", "exceptions", "sgmllib", "array", "test", "imputil", "shlex", "flp", "uu", "gdbm", "urlparse", "msilib", "termios", "modulefinder", "ossaudiodev", "timeit", "binascii", "popen2", "ConfigParser", "poplib", "zipfile", "cfmfile", "pstats", "AL", "contextlib", "code", "zipimport", "base64", "platform", "ast", "fileinput", "locale", "buildtools", "stat", "quopri", "readline", "collections", "aetypes", "concurrent", "runpy", "copy_reg", "rexec", "cmath", "optparse", "dummy_threading", "ColorPicker", "sched", "netrc", "sunaudiodev", "socketserver", "logging", "PixMapWrapper", "sysconfig", "Nav", "copy", "cmd", "csv", "chunk", "multiprocessing", "warnings", "weakref", "py_compile", "sre", "sre_parse", "curses", "threading", "re", "FrameWork", "_thread", "imgfile", "cd", "sre_constants", "xdrlib", "dataclasses", "urllib2", "StringIO", "configparser", "importlib", "UserList", "posixpath", "mailbox", "rfc822", "grp", "pydoc", "sets", "textwrap", "numbers", "W", "gl", "htmllib", "macostools", "tarfile", "ipaddress", "xmlrpc", "icopen", "traceback", "_winreg", "random", "CGIHTTPServer", "dis", "sha", "selectors", "statistics", "DocXMLRPCServer", "imghdr", "venv", "keyword", "xmlrpclib", "ftplib", "getopt", "posix", "smtpd", "profile", "sndhdr", "signal", "EasyDialogs", "dumbdbm", "fcntl", "SocketServer", "distutils", "symbol", "pathlib", "cStringIO", "imaplib", "unittest", "al", "cProfile", "robotparser", "BaseHTTPServer", "os", "pkgutil", "socket", "fractions", "shelve", "aifc", "cgitb", "xml", "decimal", "sre_compile", "ssl", "user", "Bastion", "formatter", "time", "abc", "winreg", "difflib", "FL", "bz2", "asynchat", "gc", "gensuitemodule", "symtable", "secrets", "Carbon", "mailcap", "sys", "bdb", "fpectl", "httplib", "webbrowser", "smtplib", "Cookie", "whichdb", "turtle", "tokenize", "UserString", "tabnanny", "site", "struct", "codeop", "email", "typing", "cookielib", "Queue", "rlcompleter", "errno", "macpath", "videoreader", "md5", "cPickle", "Tix", "io", "faulthandler", "Tkinter", "glob", "syslog", "telnetlib", "_dummy_thread", "hmac", "uuid", "imageop", "future_builtins", "json", "htmlentitydefs", "lib2to3", "UserDict", "mutex", "sqlite3", "findertools", "bisect", "builtins", "urllib", "http", "compileall", "argparse", "ScrolledText", "token", "dl", "applesingle", "math", "ensurepip", "mimify", "mimetools", "colorsys", "zipapp", "__builtin__", } ), extra_standard_library=frozenset(), known_other={"other": frozenset({"", "\x10\x1bm"})}, multi_line_output=0, forced_separate=(), indent=" ", comment_prefix=" #", length_sort=True, length_sort_straight=False, length_sort_sections=frozenset(), add_imports=frozenset(), remove_imports=frozenset( { "", "\U00076fe7þs\x0c\U000c8b75v\U00106541", "𥒒>\U0001960euj𒎕\x9e", "\x15\x9b", "\x02l", "\U000b71ef.\x1c", "\x7f?\U000ec91c", "\x7f,ÞoÀP8\x1b\x1e»3\x86\x94¤ÁÓ~\U00066b1a,O\U0010ab28\x90«", "Y\x06ºZ\x04Ýì\U00078ce1.\U0010c1f9[EK\x83EÖø", ";À¨|\x1b 𑐒🍸V", } ), append_only=False, reverse_relative=True, force_single_line=False, single_line_exclusions=( "Y\U000347d9g\x957K", "", "Ê\U000e8ad2\U0008fa72ùÏ\x19ç\U000eaecc𤎪.", "·o\U000d00e5\U000b36de+\x8f\U000b5953´\x08oÜ", "", ":sI¶", "", ), default_section="THIRDPARTY", import_headings={}, import_footers={}, balanced_wrapping=False, use_parentheses=True, order_by_type=True, atomic=False, lines_before_imports=-1, lines_after_imports=-1, lines_between_sections=1, lines_between_types=0, combine_as_imports=True, combine_star=False, include_trailing_comma=False, from_first=False, verbose=False, quiet=False, force_adds=False, force_alphabetical_sort_within_sections=False, force_alphabetical_sort=False, force_grid_wrap=0, force_sort_within_sections=False, lexicographical=False, ignore_whitespace=False, no_lines_before=frozenset( { "uøø", "¢", "&\x8c5Ï\U000e5f01Ø", "\U0005d415\U000a3df2h\U000f24e5\U00104d7b34¹ÒÀ", "\U000e374c8", "w", } ), no_inline_sort=False, ignore_comments=False, case_sensitive=False, sources=( { "py_version": "py3", "force_to_top": frozenset(), "skip": frozenset( { ".svn", ".venv", "build", "dist", ".bzr", ".tox", ".hg", ".mypy_cache", ".nox", "_build", "buck-out", "node_modules", ".git", ".eggs", ".pants.d", "venv", ".direnv", } ), "skip_glob": frozenset(), "skip_gitignore": False, "line_length": 79, "wrap_length": 0, "line_ending": "", "sections": ("FUTURE", "STDLIB", "THIRDPARTY", "FIRSTPARTY", "LOCALFOLDER"), "no_sections": False, "known_future_library": frozenset({"__future__"}), "known_third_party": frozenset(), "known_first_party": frozenset(), "known_local_folder": frozenset(), "known_standard_library": frozenset( { "pwd", "copy", "cmd", "csv", "chunk", "multiprocessing", "warnings", "types", "weakref", "nntplib", "pyclbr", "encodings", "py_compile", "sre", "ctypes", "sre_parse", "filecmp", "curses", "threading", "dbm", "re", "_thread", "sre_constants", "xdrlib", "dataclasses", "mimetypes", "configparser", "importlib", "msvcrt", "spwd", "posixpath", "mailbox", "codecs", "grp", "pickletools", "tkinter", "pickle", "contextvars", "pydoc", "textwrap", "numbers", "pipes", "heapq", "tarfile", "unicodedata", "ntpath", "ipaddress", "marshal", "xmlrpc", "traceback", "linecache", "calendar", "pty", "random", "dis", "selectors", "statistics", "imghdr", "venv", "inspect", "mmap", "keyword", "ftplib", "tty", "nis", "getopt", "posix", "smtpd", "wave", "profile", "sndhdr", "signal", "tracemalloc", "pdb", "sunau", "winsound", "parser", "zlib", "fcntl", "pprint", "distutils", "crypt", "symbol", "gettext", "pathlib", "asyncore", "copyreg", "imaplib", "unittest", "queue", "resource", "turtledemo", "fnmatch", "cProfile", "os", "pkgutil", "socket", "trace", "fractions", "string", "shelve", "plistlib", "aifc", "gzip", "functools", "cgitb", "xml", "hashlib", "decimal", "imp", "sre_compile", "ssl", "formatter", "winreg", "time", "getpass", "shutil", "abc", "difflib", "bz2", "operator", "reprlib", "subprocess", "cgi", "select", "asynchat", "audioop", "gc", "secrets", "symtable", "mailcap", "sys", "bdb", "fpectl", "stringprep", "webbrowser", "smtplib", "wsgiref", "atexit", "lzma", "asyncio", "datetime", "binhex", "doctest", "turtle", "enum", "tempfile", "tokenize", "tabnanny", "site", "html", "struct", "itertools", "codeop", "email", "array", "test", "typing", "shlex", "uu", "msilib", "termios", "rlcompleter", "modulefinder", "ossaudiodev", "timeit", "binascii", "poplib", "errno", "macpath", "zipfile", "io", "faulthandler", "pstats", "contextlib", "code", "glob", "zipimport", "base64", "syslog", "platform", "ast", "fileinput", "telnetlib", "locale", "_dummy_thread", "hmac", "stat", "uuid", "quopri", "readline", "collections", "json", "concurrent", "lib2to3", "sqlite3", "runpy", "cmath", "optparse", "bisect", "builtins", "urllib", "dummy_threading", "http", "compileall", "argparse", "token", "sched", "netrc", "math", "ensurepip", "socketserver", "colorsys", "zipapp", "logging", "sysconfig", } ), "extra_standard_library": frozenset(), "known_other": {}, "multi_line_output": 0, "forced_separate": (), "indent": " ", "comment_prefix": " #", "length_sort": False, "length_sort_straight": False, "length_sort_sections": frozenset(), "add_imports": frozenset(), "remove_imports": frozenset(), "append_only": False, "reverse_relative": False, "force_single_line": False, "single_line_exclusions": (), "default_section": "THIRDPARTY", "import_headings": {}, "import_footers": {}, "balanced_wrapping": False, "use_parentheses": False, "order_by_type": True, "atomic": False, "lines_before_imports": -1, "lines_after_imports": -1, "lines_between_sections": 1, "lines_between_types": 0, "combine_as_imports": False, "combine_star": False, "include_trailing_comma": False, "from_first": False, "verbose": False, "quiet": False, "force_adds": False, "force_alphabetical_sort_within_sections": False, "force_alphabetical_sort": False, "force_grid_wrap": 0, "force_sort_within_sections": False, "lexicographical": False, "ignore_whitespace": False, "no_lines_before": frozenset(), "no_inline_sort": False, "ignore_comments": False, "case_sensitive": False, "sources": (), "virtual_env": "", "conda_env": "", "ensure_newline_before_comments": False, "directory": "", "profile": "", "honor_noqa": False, "src_paths": frozenset(), "old_finders": False, "remove_redundant_aliases": False, "float_to_top": False, "filter_files": False, "formatter": "", "formatting_function": None, "color_output": False, "treat_comments_as_code": frozenset(), "treat_all_comments_as_code": False, "supported_extensions": frozenset({"py", "pyx", "pyi"}), "blocked_extensions": frozenset({"pex"}), "constants": frozenset(), "classes": frozenset(), "variables": frozenset(), "dedup_headings": False, "source": "defaults", }, { "classes": frozenset( { "\U000eb6c6\x9eÑ\U0008297dâhï\x8eÆ", "C", "\x8e\U000422ac±\U000b5a1f\U000c4166", "ùÚ", } ), "single_line_exclusions": ( "Y\U000347d9g\x957K", "", "Ê\U000e8ad2\U0008fa72ùÏ\x19ç\U000eaecc𤎪.", "·o\U000d00e5\U000b36de+\x8f\U000b5953´\x08oÜ", "", ":sI¶", "", ), "indent": " ", "no_lines_before": frozenset( { "uøø", "¢", "&\x8c5Ï\U000e5f01Ø", "\U0005d415\U000a3df2h\U000f24e5\U00104d7b34¹ÒÀ", "\U000e374c8", "w", } ), "quiet": False, "honor_noqa": False, "dedup_headings": True, "known_other": { "\x10\x1bm": frozenset({"\U000682a49\U000e1a63²KǶ4", "", "\x1a", "©"}), "": frozenset({"íå\x94Ì", "\U000cf258"}), }, "treat_comments_as_code": frozenset({""}), "length_sort": True, "reverse_relative": True, "combine_as_imports": True, "py_version": "all", "use_parentheses": True, "skip_gitignore": True, "remove_imports": frozenset( { "", "\U00076fe7þs\x0c\U000c8b75v\U00106541", "𥒒>\U0001960euj𒎕\x9e", "\x15\x9b", "\x02l", "\U000b71ef.\x1c", "\x7f?\U000ec91c", "\x7f,ÞoÀP8\x1b\x1e»3\x86\x94¤ÁÓ~\U00066b1a,O\U0010ab28\x90«", "Y\x06ºZ\x04Ýì\U00078ce1.\U0010c1f9[EK\x83EÖø", ";À¨|\x1b 𑐒🍸V", } ), "atomic": False, "source": "runtime", }, ), virtual_env="", conda_env="", ensure_newline_before_comments=False, directory="/home/abuild/rpmbuild/BUILD/isort-5.11.0", profile="", honor_noqa=False, old_finders=False, remove_redundant_aliases=False, float_to_top=False, filter_files=False, formatting_function=None, color_output=False, treat_comments_as_code=frozenset({""}), treat_all_comments_as_code=False, supported_extensions=frozenset({"py", "pyx", "pyi"}), blocked_extensions=frozenset({"pex"}), constants=frozenset(), classes=frozenset( {"\U000eb6c6\x9eÑ\U0008297dâhï\x8eÆ", "C", "\x8e\U000422ac±\U000b5a1f\U000c4166", "ùÚ"} ), variables=frozenset(), dedup_headings=True, ), disregard_skip=True, ) @hypothesis.given( config=st.from_type(isort.Config), disregard_skip=st.booleans(), ) @hypothesis.settings(deadline=None) def test_isort_doesnt_lose_imports_or_comments(config: isort.Config, disregard_skip: bool) -> None: result = isort.code(CODE_SNIPPET, config=config, disregard_skip=disregard_skip) for should_be_retained in SHOULD_RETAIN: if should_be_retained not in result: if config.ignore_comments and should_be_retained.startswith("comment"): continue assert should_be_retained in result isort-6.0.1/tests/integration/test_ticketed_features.py0000644000000000000000000000602413615410400020370 0ustar00"""Tests that need installation of other packages.""" # TODO: find a way to install example-isort-formatting-plugin to pass tests # from io import StringIO # import pytest # import isort # from isort import api, exceptions # def test_isort_supports_formatting_plugins(): # """Test to ensure isort provides a way to create and share formatting plugins. # See: https://github.com/pycqa/isort/issues/1353. # """ # # formatting plugin # assert isort.code("import a", formatter="example") == "import a\n" # # non-existent plugin # with pytest.raises(exceptions.FormattingPluginDoesNotExist): # assert isort.code("import a", formatter="madeupfake") == "import a\n" # def test_isort_literals_issue_1358(): # assert ( # isort.code( # """ # import x # import a # # isort: list # __all__ = ["b", "a", "b"] # # isort: unique-list # __all__ = ["b", "a", "b"] # # isort: tuple # __all__ = ("b", "a", "b") # # isort: unique-tuple # __all__ = ("b", "a", "b") # # isort: set # __all__ = {"b", "a", "b"} # def method(): # # isort: list # x = ["b", "a"] # # isort: dict # y = {"z": "z", "b": "b", "b": "c"}""" # ) # == """ # import a # import x # # isort: list # __all__ = ['a', 'b', 'b'] # # isort: unique-list # __all__ = ['a', 'b'] # # isort: tuple # __all__ = ('a', 'b', 'b') # # isort: unique-tuple # __all__ = ('a', 'b') # # isort: set # __all__ = {'a', 'b'} # def method(): # # isort: list # x = ['a', 'b'] # # isort: dict # y = {'b': 'c', 'z': 'z'}""" # ) # assert ( # isort.code( # """ # import x # import a # # isort: list # __all__ = ["b", "a", "b"] # # isort: unique-list # __all__ = ["b", "a", "b"] # # isort: tuple # __all__ = ("b", "a", "b") # # isort: unique-tuple # __all__ = ("b", "a", "b") # # isort: set # __all__ = {"b", "a", "b"} # def method(): # # isort: list # x = ["b", "a"] # # isort: assignments # d = 1 # b = 2 # a = 3 # # isort: dict # y = {"z": "z", "b": "b", "b": "c"}""", # formatter="example", # ) # == """ # import a # import x # # isort: list # __all__ = ["a", "b", "b"] # # isort: unique-list # __all__ = ["a", "b"] # # isort: tuple # __all__ = ("a", "b", "b") # # isort: unique-tuple # __all__ = ("a", "b") # # isort: set # __all__ = {"a", "b"} # def method(): # # isort: list # x = ["a", "b"] # # isort: assignments # a = 3 # b = 2 # d = 1 # # isort: dict # y = {"b": "c", "z": "z"}""" # ) # assert api.sort_stream( # input_stream=StringIO( # """ # import a # import x # # isort: list # __all__ = ["b", "a", "b"] # # isort: unique-list # __all__ = ["b", "a", "b"] # # isort: tuple # __all__ = ("b", "a", "b") # # isort: unique-tuple # __all__ = ("b", "a", "b") # # isort: set # __all__ = {"b", "a", "b"} # def method(): # # isort: list # x = ["b", "a"] # # isort: assignments # d = 1 # b = 2 # a = 3 # # isort: dict # y = {"z": "z", "b": "b", "b": "c"}""", # ), # output_stream=StringIO(), # ) isort-6.0.1/tests/unit/__init__.py0000644000000000000000000000000013615410400014016 0ustar00isort-6.0.1/tests/unit/conftest.py0000644000000000000000000000106313615410400014116 0ustar00"""isort test wide fixtures and configuration""" import os from pathlib import Path import pytest TEST_DIR = os.path.dirname(os.path.abspath(__file__)) SRC_DIR = os.path.abspath(os.path.join(TEST_DIR, "../../isort/")) @pytest.fixture def test_dir(): return TEST_DIR @pytest.fixture def src_dir(): return SRC_DIR @pytest.fixture def test_path(): return Path(TEST_DIR).resolve() @pytest.fixture def src_path(): return Path(SRC_DIR).resolve() @pytest.fixture def examples_path(): return Path(TEST_DIR).resolve() / "example_projects" isort-6.0.1/tests/unit/example_crlf_file.py0000644000000000000000000000015313615410400015730 0ustar00import b import a def func(): x = 1 y = 2 z = 3 c = 4 return x + y + z + c isort-6.0.1/tests/unit/test_action_comments.py0000644000000000000000000000117413615410400016515 0ustar00"""Tests for isort action comments, such as isort: skip""" import isort def test_isort_off_and_on(): """Test so ensure isort: off action comment and associated on action comment work together""" # as top of file comment assert ( isort.code( """# isort: off import a import a # isort: on import a import a """ ) == """# isort: off import a import a # isort: on import a """ ) # as middle comment assert ( isort.code( """ import a import a # isort: off import a import a """ ) == """ import a # isort: off import a import a """ ) isort-6.0.1/tests/unit/test_api.py0000644000000000000000000000746313615410400014113 0ustar00"""Tests the isort API module""" import os from io import StringIO from unittest.mock import MagicMock, patch import pytest from isort import ImportKey, api from isort.settings import Config imperfect_content = "import b\nimport a\n" fixed_content = "import a\nimport b\n" fixed_diff = "+import a\n import b\n-import a\n" @pytest.fixture def imperfect(tmpdir): imperfect_file = tmpdir.join("test_needs_changes.py") imperfect_file.write_text(imperfect_content, "utf8") return imperfect_file def test_sort_file_with_bad_syntax(tmpdir) -> None: tmp_file = tmpdir.join("test_bad_syntax.py") tmp_file.write_text("""print('mismatching quotes")""", "utf8") with pytest.warns(UserWarning): api.sort_file(tmp_file, atomic=True) with pytest.warns(UserWarning): api.sort_file(tmp_file, atomic=True, write_to_stdout=True) def test_sort_file(imperfect) -> None: assert api.sort_file(imperfect) assert imperfect.read() == fixed_content def test_sort_file_in_place(imperfect) -> None: assert api.sort_file(imperfect, overwrite_in_place=True) assert imperfect.read() == fixed_content def test_sort_file_to_stdout(capsys, imperfect) -> None: assert api.sort_file(imperfect, write_to_stdout=True) out, _ = capsys.readouterr() assert out == fixed_content.replace("\n", os.linesep) def test_other_ask_to_apply(imperfect) -> None: # First show diff, but ensure change wont get written by asking to apply # and ensuring answer is no. with patch("isort.format.input", MagicMock(return_value="n")): assert not api.sort_file(imperfect, ask_to_apply=True) assert imperfect.read() == imperfect_content # Then run again, but apply the change (answer is yes) with patch("isort.format.input", MagicMock(return_value="y")): assert api.sort_file(imperfect, ask_to_apply=True) assert imperfect.read() == fixed_content def test_check_file_no_changes(capsys, tmpdir) -> None: perfect = tmpdir.join("test_no_changes.py") perfect.write_text("import a\nimport b\n", "utf8") assert api.check_file(perfect, show_diff=True) out, _ = capsys.readouterr() assert not out def test_check_file_with_changes(capsys, imperfect) -> None: assert not api.check_file(imperfect, show_diff=True) out, _ = capsys.readouterr() assert fixed_diff.replace("\n", os.linesep) in out def test_sorted_imports_multiple_configs() -> None: with pytest.raises(ValueError, match="You can either specify custom configuration options"): api.sort_code_string("import os", config=Config(line_length=80), line_length=80) def test_diff_stream() -> None: output = StringIO() assert api.sort_stream(StringIO("import b\nimport a\n"), output, show_diff=True) output.seek(0) assert fixed_diff in output.read() def test_sort_code_string_mixed_newlines(): assert api.sort_code_string("import A\n\r\nimportA\n\n") == "import A\r\n\r\nimportA\r\n\n" def test_find_imports_in_file(imperfect): found_imports = list(api.find_imports_in_file(imperfect)) assert "b" in [found_import.module for found_import in found_imports] def test_find_imports_in_file_error(tmpdir): test_path = tmpdir.join("test_path.py") test_path.mkdir() with pytest.warns(UserWarning): assert not list(api.find_imports_in_file(test_path)) def test_find_imports_in_code(): code = """ from x.y import z as a from x.y import z as a from x.y import z import x.y import x """ assert len(list(api.find_imports_in_code(code))) == 5 assert len(list(api.find_imports_in_code(code, unique=True))) == 4 assert len(list(api.find_imports_in_code(code, unique=ImportKey.ATTRIBUTE))) == 3 assert len(list(api.find_imports_in_code(code, unique=ImportKey.MODULE))) == 2 assert len(list(api.find_imports_in_code(code, unique=ImportKey.PACKAGE))) == 1 isort-6.0.1/tests/unit/test_comments.py0000644000000000000000000000156013615410400015157 0ustar00from hypothesis import given from hypothesis import strategies as st import isort.comments def test_add_to_line(): assert ( isort.comments.add_to_line([], "import os # comment", removed=True).strip() == "import os" ) # These tests were written by the `hypothesis.extra.ghostwriter` module # and is provided under the Creative Commons Zero public domain dedication. @given( comments=st.one_of(st.none(), st.lists(st.text())), original_string=st.text(), removed=st.booleans(), comment_prefix=st.text(), ) def test_fuzz_add_to_line(comments, original_string, removed, comment_prefix): isort.comments.add_to_line( comments=comments, original_string=original_string, removed=removed, comment_prefix=comment_prefix, ) @given(line=st.text()) def test_fuzz_parse(line): isort.comments.parse(line=line) isort-6.0.1/tests/unit/test_deprecated_finders.py0000644000000000000000000001413413615410400017145 0ustar00import importlib.machinery import os import posixpath from pathlib import Path from unittest.mock import patch from isort import sections, settings from isort.deprecated import finders from isort.deprecated.finders import FindersManager from isort.settings import Config class TestFindersManager: def test_init(self): assert FindersManager(settings.DEFAULT_CONFIG) class ExceptionOnInit(finders.BaseFinder): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) raise ValueError("test") with patch( "isort.deprecated.finders.FindersManager._default_finders_classes", (*FindersManager._default_finders_classes, ExceptionOnInit), ): assert FindersManager(settings.Config(verbose=True)) def test_no_finders(self): assert FindersManager(settings.DEFAULT_CONFIG, []).find("isort") is None def test_find_broken_finder(self): class ExceptionOnFind(finders.BaseFinder): def find(*args, **kwargs): raise ValueError("test") assert ( FindersManager(settings.Config(verbose=True), [ExceptionOnFind]).find("isort") is None ) class AbstractTestFinder: kind = finders.BaseFinder @classmethod def setup_class(cls): cls.instance = cls.kind(settings.DEFAULT_CONFIG) # type: ignore def test_create(self): assert self.kind(settings.DEFAULT_CONFIG) # type: ignore def test_find(self): self.instance.find("isort") # type: ignore self.instance.find("") # type: ignore class TestForcedSeparateFinder(AbstractTestFinder): kind = finders.ForcedSeparateFinder class TestDefaultFinder(AbstractTestFinder): kind = finders.DefaultFinder class TestKnownPatternFinder(AbstractTestFinder): kind = finders.KnownPatternFinder class TestLocalFinder(AbstractTestFinder): kind = finders.LocalFinder class TestPathFinder(AbstractTestFinder): kind = finders.PathFinder def test_conda_and_virtual_env(self, tmpdir): python3lib = tmpdir.mkdir("lib").mkdir("python3") python3lib.mkdir("site-packages").mkdir("y") python3lib.mkdir("n").mkdir("site-packages").mkdir("x") tmpdir.mkdir("z").join("__init__.py").write("__version__ = '1.0.0'") tmpdir.chdir() conda = self.kind(settings.Config(conda_env=str(tmpdir)), str(tmpdir)) venv = self.kind(settings.Config(virtual_env=str(tmpdir)), str(tmpdir)) assert conda.find("y") == venv.find("y") == "THIRDPARTY" assert conda.find("x") == venv.find("x") == "THIRDPARTY" assert conda.find("z") == "THIRDPARTY" assert conda.find("os") == venv.find("os") == "STDLIB" def test_default_section(self, tmpdir): tmpdir.join("file.py").write("import b\nimport a\n") assert self.kind(settings.Config(default_section="CUSTOM"), tmpdir).find("file") == "CUSTOM" def test_src_paths(self, tmpdir): tmpdir.join("file.py").write("import b\nimport a\n") assert ( self.kind(settings.Config(src_paths=[Path(str(tmpdir))]), tmpdir).find("file") == settings.DEFAULT_CONFIG.default_section ) class TestRequirementsFinder(AbstractTestFinder): kind = finders.RequirementsFinder def test_no_pipreqs(self): with patch("isort.deprecated.finders.pipreqs", None): assert not self.kind(settings.DEFAULT_CONFIG).find("isort") def test_not_enabled(self): test_finder = self.kind(settings.DEFAULT_CONFIG) test_finder.enabled = False assert not test_finder.find("isort") def test_requirements_dir(self, tmpdir): tmpdir.mkdir("requirements").join("development.txt").write("x==1.00") test_finder = self.kind(settings.DEFAULT_CONFIG, str(tmpdir)) assert test_finder.find("x") def test_requirements_finder(tmpdir) -> None: subdir = tmpdir.mkdir("subdir").join("lol.txt") subdir.write("flask") req_file = tmpdir.join("requirements.txt") req_file.write("Django==1.11\n-e git+https://github.com/orsinium/deal.git#egg=deal\n") for path in (str(tmpdir), str(subdir)): finder = finders.RequirementsFinder(config=Config(), path=path) files = list(finder._get_files()) assert len(files) == 1 # file finding assert files[0].endswith("requirements.txt") # file finding assert set(finder._get_names(str(req_file))) == {"Django", "deal"} # file parsing assert finder.find("django") == sections.THIRDPARTY # package in reqs assert finder.find("flask") is None # package not in reqs assert finder.find("deal") == sections.THIRDPARTY # vcs assert len(finder.mapping) > 100 # type: ignore assert finder._normalize_name("deal") == "deal" assert finder._normalize_name("Django") == "django" # lowercase assert finder._normalize_name("django_haystack") == "haystack" # mapping assert finder._normalize_name("Flask-RESTful") == "flask_restful" # convert `-`to `_` req_file.remove() def test_path_finder(monkeypatch) -> None: config = config = Config() finder = finders.PathFinder(config=config) third_party_prefix = next(path for path in finder.paths if "site-packages" in path) ext_suffixes = importlib.machinery.EXTENSION_SUFFIXES imaginary_paths = { posixpath.join(finder.stdlib_lib_prefix, "example_1.py"), posixpath.join(third_party_prefix, "example_2.py"), posixpath.join(os.getcwd(), "example_3.py"), } imaginary_paths.update( { posixpath.join(third_party_prefix, "example_" + str(i) + ext_suffix) for i, ext_suffix in enumerate(ext_suffixes, 4) } ) monkeypatch.setattr( "isort.deprecated.finders.exists_case_sensitive", lambda p: p in imaginary_paths ) assert finder.find("example_1") == sections.STDLIB assert finder.find("example_2") == sections.THIRDPARTY assert finder.find("example_3") == settings.DEFAULT_CONFIG.default_section for i, _ in enumerate(ext_suffixes, 4): assert finder.find("example_" + str(i)) == sections.THIRDPARTY isort-6.0.1/tests/unit/test_exceptions.py0000644000000000000000000000757513615410400015527 0ustar00import pickle from isort import exceptions class TestISortError: def setup_class(self): self.instance = exceptions.ISortError() def test_init(self): assert isinstance(self.instance, exceptions.ISortError) def test_pickleable(self): assert isinstance(pickle.loads(pickle.dumps(self.instance)), exceptions.ISortError) class TestExistingSyntaxErrors(TestISortError): def setup_class(self): self.instance: exceptions.ExistingSyntaxErrors = exceptions.ExistingSyntaxErrors( "file_path" ) def test_variables(self): assert self.instance.file_path == "file_path" class TestIntroducedSyntaxErrors(TestISortError): def setup_class(self): self.instance: exceptions.IntroducedSyntaxErrors = exceptions.IntroducedSyntaxErrors( "file_path" ) def test_variables(self): assert self.instance.file_path == "file_path" class TestFileSkipped(TestISortError): def setup_class(self): self.instance: exceptions.FileSkipped = exceptions.FileSkipped("message", "file_path") def test_variables(self): assert self.instance.file_path == "file_path" assert str(self.instance) == "message" class TestFileSkipComment(TestISortError): def setup_class(self): self.instance: exceptions.FileSkipComment = exceptions.FileSkipComment("file_path") def test_variables(self): assert self.instance.file_path == "file_path" class TestFileSkipSetting(TestISortError): def setup_class(self): self.instance: exceptions.FileSkipSetting = exceptions.FileSkipSetting("file_path") def test_variables(self): assert self.instance.file_path == "file_path" class TestProfileDoesNotExist(TestISortError): def setup_class(self): self.instance: exceptions.ProfileDoesNotExist = exceptions.ProfileDoesNotExist("profile") def test_variables(self): assert self.instance.profile == "profile" class TestSortingFunctionDoesNotExist(TestISortError): def setup_class(self): self.instance: exceptions.SortingFunctionDoesNotExist = ( exceptions.SortingFunctionDoesNotExist("round", ["square", "peg"]) ) def test_variables(self): assert self.instance.sort_order == "round" assert self.instance.available_sort_orders == ["square", "peg"] class TestLiteralParsingFailure(TestISortError): def setup_class(self): self.instance: exceptions.LiteralParsingFailure = exceptions.LiteralParsingFailure( "x = [", SyntaxError ) def test_variables(self): assert self.instance.code == "x = [" assert self.instance.original_error is SyntaxError class TestLiteralSortTypeMismatch(TestISortError): def setup_class(self): self.instance: exceptions.LiteralSortTypeMismatch = exceptions.LiteralSortTypeMismatch( tuple, list ) def test_variables(self): assert self.instance.kind is tuple assert self.instance.expected_kind is list class TestAssignmentsFormatMismatch(TestISortError): def setup_class(self): self.instance: exceptions.AssignmentsFormatMismatch = exceptions.AssignmentsFormatMismatch( "print x" ) def test_variables(self): assert self.instance.code == "print x" class TestUnsupportedSettings(TestISortError): def setup_class(self): self.instance: exceptions.UnsupportedSettings = exceptions.UnsupportedSettings( {"apply": {"value": "true", "source": "/"}} ) def test_variables(self): assert self.instance.unsupported_settings == {"apply": {"value": "true", "source": "/"}} class TestUnsupportedEncoding(TestISortError): def setup_class(self): self.instance: exceptions.UnsupportedEncoding = exceptions.UnsupportedEncoding("file.py") def test_variables(self): assert self.instance.filename == "file.py" isort-6.0.1/tests/unit/test_files.py0000644000000000000000000000037113615410400014433 0ustar00from isort import files from isort.settings import DEFAULT_CONFIG def test_find(tmpdir): tmp_file = tmpdir.join("file.py") tmp_file.write("import os, sys\n") assert tuple(files.find((tmp_file,), DEFAULT_CONFIG, [], [])) == (tmp_file,) isort-6.0.1/tests/unit/test_format.py0000644000000000000000000001054013615410400014620 0ustar00from io import StringIO from pathlib import Path from unittest.mock import MagicMock, patch import colorama import pytest from hypothesis import given, reject from hypothesis import strategies as st import isort.format def test_ask_whether_to_apply_changes_to_file(): with patch("isort.format.input", MagicMock(return_value="y")): assert isort.format.ask_whether_to_apply_changes_to_file("") with patch("isort.format.input", MagicMock(return_value="n")): assert not isort.format.ask_whether_to_apply_changes_to_file("") with patch("isort.format.input", MagicMock(return_value="q")): with pytest.raises(SystemExit): assert isort.format.ask_whether_to_apply_changes_to_file("") def test_basic_printer(capsys): printer = isort.format.create_terminal_printer( color=False, success="{success}: {message}", error="{error}: {message}" ) printer.success("All good!") out, _ = capsys.readouterr() assert out == "SUCCESS: All good!\n" printer.error("Some error") _, err = capsys.readouterr() assert err == "ERROR: Some error\n" printer = isort.format.create_terminal_printer( color=False, success="success: {message}: {success}", error="error: {message}: {error}" ) printer.success("All good!") out, _ = capsys.readouterr() assert out == "success: All good!: SUCCESS\n" printer.error("Some error") _, err = capsys.readouterr() assert err == "error: Some error: ERROR\n" def test_basic_printer_diff(capsys): printer = isort.format.create_terminal_printer(color=False) printer.diff_line("+ added line\n") printer.diff_line("- removed line\n") out, _ = capsys.readouterr() assert out == "+ added line\n- removed line\n" def test_colored_printer_success(capsys): printer = isort.format.create_terminal_printer(color=True, success="{success}: {message}") printer.success("All good!") out, _ = capsys.readouterr() assert "SUCCESS" in out assert "All good!" in out assert colorama.Fore.GREEN in out def test_colored_printer_error(capsys): printer = isort.format.create_terminal_printer(color=True, error="{error}: {message}") printer.error("Some error") _, err = capsys.readouterr() assert "ERROR" in err assert "Some error" in err assert colorama.Fore.RED in err def test_colored_printer_diff(capsys): printer = isort.format.create_terminal_printer(color=True) printer.diff_line("+++ file1\n") printer.diff_line("--- file2\n") printer.diff_line("+ added line\n") printer.diff_line("normal line\n") printer.diff_line("- removed line\n") printer.diff_line("normal line\n") out, _ = capsys.readouterr() # No color added to lines with multiple + and -'s assert out.startswith("+++ file1\n--- file2\n") # Added lines are green assert colorama.Fore.GREEN + "+ added line" in out # Removed lines are red assert colorama.Fore.RED + "- removed line" in out # Normal lines are reset back assert colorama.Style.RESET_ALL + "normal line" in out def test_colored_printer_diff_output(capsys): output = StringIO() printer = isort.format.create_terminal_printer(color=True, output=output) printer.diff_line("a line\n") out, _ = capsys.readouterr() assert out == "" output.seek(0) assert output.read().startswith("a line\n") @patch("isort.format.colorama_unavailable", True) def test_colorama_not_available_handled_gracefully(capsys): with pytest.raises(SystemExit) as system_exit: _ = isort.format.create_terminal_printer(color=True) assert system_exit.value.code assert int(system_exit.value.code) > 0 _, err = capsys.readouterr() assert "colorama" in err assert "colors extra" in err # This test code was written by the `hypothesis.extra.ghostwriter` module # and is provided under the Creative Commons Zero public domain dedication. @given( file_input=st.text(), file_output=st.text(), file_path=st.one_of(st.none(), st.builds(Path)), output=st.one_of(st.none(), st.builds(StringIO, st.text())), ) def test_fuzz_show_unified_diff(file_input, file_output, file_path, output): try: isort.format.show_unified_diff( file_input=file_input, file_output=file_output, file_path=file_path, output=output, ) except UnicodeEncodeError: reject() isort-6.0.1/tests/unit/test_hooks.py0000644000000000000000000000753213615410400014462 0ustar00import os from pathlib import Path from unittest.mock import MagicMock, patch from isort import exceptions, hooks def test_git_hook(src_dir): """Simple smoke level testing of git hooks""" # Ensure correct subprocess command is called with patch("subprocess.run", MagicMock()) as run_mock: hooks.git_hook() run_mock.assert_called_once() assert run_mock.call_args[0][0] == [ "git", "diff-index", "--cached", "--name-only", "--diff-filter=ACMRTUXB", "HEAD", ] with patch("subprocess.run", MagicMock()) as run_mock: hooks.git_hook(lazy=True) run_mock.assert_called_once() assert run_mock.call_args[0][0] == [ "git", "diff-index", "--name-only", "--diff-filter=ACMRTUXB", "HEAD", ] # Test that non python files aren't processed with patch( "isort.hooks.get_lines", MagicMock(return_value=["README.md", "setup.cfg", "LICDENSE", "mkdocs.yml", "test"]), ): with patch("subprocess.run", MagicMock()) as run_mock: hooks.git_hook(modify=True) run_mock.assert_not_called() mock_main_py = MagicMock(return_value=[os.path.join(src_dir, "main.py")]) mock_imperfect = MagicMock() mock_imperfect.return_value.stdout = b"import b\nimport a" # Test with incorrectly sorted file returned from git with patch("isort.hooks.get_lines", mock_main_py): with patch("subprocess.run", mock_imperfect): with patch("isort.api.sort_file", MagicMock(return_value=False)) as api_mock: hooks.git_hook(modify=True) api_mock.assert_called_once() assert api_mock.call_args[0][0] == mock_main_py.return_value[0] # Test with sorted file returned from git and modify=False with patch("isort.hooks.get_lines", mock_main_py): with patch("subprocess.run", mock_imperfect): with patch("isort.api.sort_file", MagicMock(return_value=False)) as api_mock: hooks.git_hook(modify=False) api_mock.assert_not_called() # Test with skipped file returned from git with patch( "isort.hooks.get_lines", MagicMock(return_value=[os.path.join(src_dir, "main.py")]) ) as run_mock: class FakeProcessResponse: stdout = b"# isort: skip-file\nimport b\nimport a\n" with patch("subprocess.run", MagicMock(return_value=FakeProcessResponse())) as run_mock: with patch("isort.api", MagicMock(side_effect=exceptions.FileSkipped("", ""))): hooks.git_hook(modify=True) def test_git_hook_uses_the_configuration_file_specified_in_settings_path(tmp_path: Path) -> None: subdirectory_path = tmp_path / "subdirectory" configuration_file_path = subdirectory_path / ".isort.cfg" # Inserting the modified file in the parent directory of the configuration file ensures that it # will not be found by the normal search routine modified_file_path = configuration_file_path.parent.parent / "somefile.py" # This section will be used to check that the configuration file was indeed loaded section = "testsection" os.mkdir(subdirectory_path) with open(configuration_file_path, "w") as fd: fd.write("[isort]\n") fd.write(f"sections={section}") with open(modified_file_path, "w") as fd: pass files_modified = [str(modified_file_path.absolute())] with patch("isort.hooks.get_lines", MagicMock(return_value=files_modified)): with patch("isort.hooks.get_output", MagicMock(return_value="")): with patch("isort.api.check_code_string", MagicMock()) as run_mock: hooks.git_hook(settings_file=str(configuration_file_path)) assert run_mock.call_args[1]["config"].sections == (section,) isort-6.0.1/tests/unit/test_identify.py0000644000000000000000000001023013615410400015137 0ustar00from io import StringIO from typing import List from isort import Config, identify from isort.identify import Import def imports_in_code(code: str, **kwargs) -> List[identify.Import]: return list(identify.imports(StringIO(code), **kwargs)) def test_top_only(): imports_in_function = """ import abc def xyz(): import defg """ assert len(imports_in_code(imports_in_function)) == 2 assert len(imports_in_code(imports_in_function, top_only=True)) == 1 imports_after_class = """ import abc class MyObject: pass import defg """ assert len(imports_in_code(imports_after_class)) == 2 assert len(imports_in_code(imports_after_class, top_only=True)) == 1 def test_top_doc_string(): assert ( len( imports_in_code( ''' #! /bin/bash import x """import abc from y import z """ import abc ''' ) ) == 1 ) def test_yield_and_raise_edge_cases(): assert not imports_in_code( """ raise SomeException("Blah") \\ from exceptionsInfo.popitem()[1] """ ) assert not imports_in_code( """ def generator_function(): yield \\ from other_function()[1] """ ) assert ( len( imports_in_code( """ # one # two def function(): # three \\ import b import a """ ) ) == 2 ) assert ( len( imports_in_code( """ # one # two def function(): raise \\ import b import a """ ) ) == 1 ) assert not imports_in_code( """ def generator_function(): ( yield from other_function()[1] ) """ ) assert not imports_in_code( """ def generator_function(): ( ( (((( ((((( (( ((( yield from other_function()[1] ))))))))))))) ))) """ ) assert ( len( imports_in_code( """ def generator_function(): import os yield \\ from other_function()[1] """ ) ) == 1 ) assert not imports_in_code( """ def generator_function(): ( ( (((( ((((( (( ((( yield """ ) assert not imports_in_code( """ def generator_function(): ( ( (((( ((((( (( ((( raise ( """ ) assert not imports_in_code( """ def generator_function(): ( ( (((( ((((( (( ((( raise \\ from \\ """ ) assert ( len( imports_in_code( """ def generator_function(): ( ( (((( ((((( (( ((( raise \\ from \\ import c import abc import xyz """ ) ) == 2 ) def test_complex_examples(): assert ( len( imports_in_code( """ import a, b, c; import n x = ( 1, 2, 3 ) import x from os \\ import path from os ( import path ) from os import \\ path from os \\ import ( path ) from os import ( \\""" ) ) == 9 ) assert not imports_in_code("from os import \\") assert ( imports_in_code( """ from os \\ import ( system""" ) == [ Import( line_number=2, indented=False, module="os", attribute="system", alias=None, cimport=False, file_path=None, ) ] ) def test_aliases(): assert imports_in_code("import os as os")[0].alias == "os" assert not imports_in_code( "import os as os", config=Config( remove_redundant_aliases=True, ), )[0].alias assert imports_in_code("from os import path as path")[0].alias == "path" assert not imports_in_code( "from os import path as path", config=Config(remove_redundant_aliases=True) )[0].alias def test_indented(): assert not imports_in_code("import os")[0].indented assert imports_in_code(" import os")[0].indented assert imports_in_code("\timport os")[0].indented isort-6.0.1/tests/unit/test_importable.py0000644000000000000000000000226213615410400015470 0ustar00"""Basic set of tests to ensure entire code base is importable""" import pytest def test_importable(): """Simple smoketest to ensure all isort modules are importable""" import isort import isort._version import isort.api import isort.comments import isort.deprecated.finders import isort.exceptions import isort.format import isort.hooks import isort.logo import isort.main import isort.output import isort.parse import isort.place import isort.profiles import isort.pylama_isort import isort.sections import isort.settings import isort.setuptools_commands import isort.sorting import isort.stdlibs import isort.stdlibs.all import isort.stdlibs.py2 import isort.stdlibs.py3 import isort.stdlibs.py27 import isort.stdlibs.py36 import isort.stdlibs.py37 import isort.stdlibs.py38 import isort.stdlibs.py39 import isort.stdlibs.py310 import isort.stdlibs.py311 import isort.stdlibs.py312 import isort.stdlibs.py313 import isort.utils import isort.wrap import isort.wrap_modes with pytest.raises(SystemExit): import isort.__main__ # noqa: F401 isort-6.0.1/tests/unit/test_io.py0000644000000000000000000000274713615410400013751 0ustar00import sys from unittest.mock import patch import pytest from isort import io from isort.exceptions import UnsupportedEncoding class TestFile: @pytest.mark.skipif(sys.platform == "win32", reason="Can't run file encoding test in AppVeyor") def test_read(self, tmpdir): test_file_content = """# -*- encoding: ascii -*- import Ὡ """ test_file = tmpdir.join("file.py") test_file.write(test_file_content) with pytest.raises(UnicodeDecodeError): with io.File.read(str(test_file)) as file_handler: file_handler.stream.read() def test_from_content(self, tmpdir): test_file = tmpdir.join("file.py") test_file.write_text("import os", "utf8") file_obj = io.File.from_contents("import os", filename=str(test_file)) assert file_obj assert file_obj.extension == "py" def test_open(self, tmpdir): with pytest.raises(FileNotFoundError): io.File._open("THISCANTBEAREALFILEὩὩὩὩὩὩὩὩὩὩὩὩ.ὩὩὩὩὩ") def raise_arbitrary_exception(*args, **kwargs): raise RuntimeError("test") test_file = tmpdir.join("file.py") test_file.write("import os") assert io.File._open(str(test_file)) # correctly responds to error determining encoding with patch("tokenize.detect_encoding", raise_arbitrary_exception): with pytest.raises(UnsupportedEncoding): io.File._open(str(test_file)) isort-6.0.1/tests/unit/test_isort.py0000644000000000000000000055423413615410400014505 0ustar00"""Tests all major functionality of the isort library Should be ran using py.test by simply running py.test in the isort project directory """ import os import os.path import subprocess import sys from io import StringIO from pathlib import Path from tempfile import NamedTemporaryFile from typing import TYPE_CHECKING, Any, Iterator, List, Set, Tuple import pytest import isort from isort import api, files, sections from isort.exceptions import ExistingSyntaxErrors, FileSkipped, MissingSection from isort.settings import Config from isort.utils import exists_case_sensitive from .utils import UnreadableStream, as_stream if TYPE_CHECKING: from typing import Dict # noqa: F401 WrapModes: Any else: from isort.wrap_modes import WrapModes TEST_DEFAULT_CONFIG = """ [*.{py,pyi}] max_line_length = 120 indent_style = space indent_size = 4 known_first_party = isort known_third_party = kate known_something_else = something_entirely_different sections = FUTURE, STDLIB, THIRDPARTY, FIRSTPARTY, LOCALFOLDER, SOMETHING_ELSE ignore_frosted_errors = E103 skip = build,.tox,venv balanced_wrapping = true """ SHORT_IMPORT = "from third_party import lib1, lib2, lib3, lib4" SINGLE_FROM_IMPORT = "from third_party import lib1" SINGLE_LINE_LONG_IMPORT = "from third_party import lib1, lib2, lib3, lib4, lib5, lib5ab" REALLY_LONG_IMPORT = ( "from third_party import lib1, lib2, lib3, lib4, lib5, lib6, lib7, lib8, lib9, lib10, lib11," "lib12, lib13, lib14, lib15, lib16, lib17, lib18, lib20, lib21, lib22" ) REALLY_LONG_IMPORT_WITH_COMMENT = ( "from third_party import lib1, lib2, lib3, lib4, lib5, lib6, lib7, lib8, lib9, " "lib10, lib11, lib12, lib13, lib14, lib15, lib16, lib17, lib18, lib20, lib21, lib22" " # comment" ) @pytest.fixture(scope="session", autouse=True) def default_settings_path(tmpdir_factory) -> Iterator[str]: config_dir = tmpdir_factory.mktemp("config") config_file = config_dir.join(".editorconfig").strpath with open(config_file, "w") as editorconfig: editorconfig.write(TEST_DEFAULT_CONFIG) assert Config(config_file).known_other with config_dir.as_cwd(): yield config_dir.strpath def test_happy_path() -> None: """Test the most basic use case, straight imports no code, simply not organized by category.""" test_input = "import sys\nimport os\nimport myproject.test\nimport django.settings" test_output = isort.code(test_input, known_first_party=["myproject"]) assert test_output == ( "import os\n" "import sys\n" "\n" "import django.settings\n" "\n" "import myproject.test\n" ) def test_code_intermixed() -> None: """Defines what should happen when isort encounters imports intermixed with code. (it should pull them all to the top) """ test_input = ( "import sys\n" "print('yo')\n" "print('I like to put code between imports cause I want stuff to break')\n" "import myproject.test\n" ) test_output = isort.code(test_input) assert test_output == ( "import sys\n" "\n" "print('yo')\n" "print('I like to put code between imports cause I want stuff to break')\n" "import myproject.test\n" ) def test_correct_space_between_imports() -> None: """Ensure after imports a correct amount of space (in newlines) is enforced. (2 for method, class, or decorator definitions 1 for anything else) """ test_input_method = "import sys\ndef my_method():\n print('hello world')\n" test_output_method = isort.code(test_input_method) assert test_output_method == ("import sys\n\n\ndef my_method():\n print('hello world')\n") test_input_decorator = ( "import sys\n" "@my_decorator\n" "def my_method():\n" " print('hello world')\n" ) test_output_decorator = isort.code(test_input_decorator) assert test_output_decorator == ( "import sys\n" "\n" "\n" "@my_decorator\n" "def my_method():\n" " print('hello world')\n" ) test_input_class = "import sys\nclass MyClass(object):\n pass\n" test_output_class = isort.code(test_input_class) assert test_output_class == "import sys\n\n\nclass MyClass(object):\n pass\n" test_input_other = "import sys\nprint('yo')\n" test_output_other = isort.code(test_input_other) assert test_output_other == "import sys\n\nprint('yo')\n" test_input_inquotes = ( "import sys\n" "@my_decorator('''hello\nworld''')\n" "def my_method():\n" " print('hello world')\n" ) test_output_inquotes = api.sort_code_string(test_input_inquotes) assert ( test_output_inquotes == "import sys\n" "\n\n" "@my_decorator('''hello\nworld''')\n" "def my_method():\n" " print('hello world')\n" ) test_input_assign = "import sys\nVAR = 1\n" test_output_assign = api.sort_code_string(test_input_assign) assert test_output_assign == "import sys\n\nVAR = 1\n" test_input_assign = "import sys\nVAR = 1\ndef y():\n" test_output_assign = api.sort_code_string(test_input_assign) assert test_output_assign == "import sys\n\nVAR = 1\ndef y():\n" test_input = """ import os x = "hi" def x(): pass """ assert isort.code(test_input) == test_input def test_sort_on_number() -> None: """Ensure numbers get sorted logically (10 > 9 not the other way around)""" test_input = "import lib10\nimport lib9\n" test_output = isort.code(test_input) assert test_output == "import lib9\nimport lib10\n" def test_line_length() -> None: """Ensure isort enforces the set line_length.""" assert len(isort.code(REALLY_LONG_IMPORT, line_length=80).split("\n")[0]) <= 80 assert len(isort.code(REALLY_LONG_IMPORT, line_length=120).split("\n")[0]) <= 120 test_output = isort.code(REALLY_LONG_IMPORT, line_length=42) assert test_output == ( "from third_party import (lib1, lib2, lib3,\n" " lib4, lib5, lib6,\n" " lib7, lib8, lib9,\n" " lib10, lib11,\n" " lib12, lib13,\n" " lib14, lib15,\n" " lib16, lib17,\n" " lib18, lib20,\n" " lib21, lib22)\n" ) test_input = ( "from django.contrib.gis.gdal.field import (\n" " OFTDate, OFTDateTime, OFTInteger, OFTInteger64, OFTReal, OFTString,\n" " OFTTime,\n" ")\n" ) # Test case described in issue #654 assert ( isort.code( code=test_input, include_trailing_comma=True, line_length=79, multi_line_output=WrapModes.VERTICAL_GRID_GROUPED, balanced_wrapping=False, ) == test_input ) test_output = isort.code(code=REALLY_LONG_IMPORT, line_length=42, wrap_length=32) assert test_output == ( "from third_party import (lib1,\n" " lib2,\n" " lib3,\n" " lib4,\n" " lib5,\n" " lib6,\n" " lib7,\n" " lib8,\n" " lib9,\n" " lib10,\n" " lib11,\n" " lib12,\n" " lib13,\n" " lib14,\n" " lib15,\n" " lib16,\n" " lib17,\n" " lib18,\n" " lib20,\n" " lib21,\n" " lib22)\n" ) test_input = ( "from .test import a_very_long_function_name_that_exceeds_the_normal_pep8_line_length\n" ) with pytest.raises(ValueError, match="wrap_length must be set lower than or equal to line_le"): test_output = isort.code(code=REALLY_LONG_IMPORT, line_length=80, wrap_length=99) assert ( isort.code(REALLY_LONG_IMPORT, line_length=100, wrap_length=99) == """ from third_party import (lib1, lib2, lib3, lib4, lib5, lib6, lib7, lib8, lib9, lib10, lib11, lib12, lib13, lib14, lib15, lib16, lib17, lib18, lib20, lib21, lib22) """.lstrip() ) # Test Case described in issue #1015 test_output = isort.code( REALLY_LONG_IMPORT, line_length=25, multi_line_output=WrapModes.HANGING_INDENT ) assert test_output == ( "from third_party import \\\n" " lib1, lib2, lib3, \\\n" " lib4, lib5, lib6, \\\n" " lib7, lib8, lib9, \\\n" " lib10, lib11, \\\n" " lib12, lib13, \\\n" " lib14, lib15, \\\n" " lib16, lib17, \\\n" " lib18, lib20, \\\n" " lib21, lib22\n" ) def test_output_modes() -> None: """Test setting isort to use various output modes works as expected""" test_output_grid = isort.code( code=REALLY_LONG_IMPORT, multi_line_output=WrapModes.GRID, line_length=40 ) assert test_output_grid == ( "from third_party import (lib1, lib2,\n" " lib3, lib4,\n" " lib5, lib6,\n" " lib7, lib8,\n" " lib9, lib10,\n" " lib11, lib12,\n" " lib13, lib14,\n" " lib15, lib16,\n" " lib17, lib18,\n" " lib20, lib21,\n" " lib22)\n" ) test_output_vertical = isort.code( code=REALLY_LONG_IMPORT, multi_line_output=WrapModes.VERTICAL, line_length=40 ) assert test_output_vertical == ( "from third_party import (lib1,\n" " lib2,\n" " lib3,\n" " lib4,\n" " lib5,\n" " lib6,\n" " lib7,\n" " lib8,\n" " lib9,\n" " lib10,\n" " lib11,\n" " lib12,\n" " lib13,\n" " lib14,\n" " lib15,\n" " lib16,\n" " lib17,\n" " lib18,\n" " lib20,\n" " lib21,\n" " lib22)\n" ) comment_output_vertical = isort.code( code=REALLY_LONG_IMPORT_WITH_COMMENT, multi_line_output=WrapModes.VERTICAL, line_length=40 ) assert comment_output_vertical == ( "from third_party import (lib1, # comment\n" " lib2,\n" " lib3,\n" " lib4,\n" " lib5,\n" " lib6,\n" " lib7,\n" " lib8,\n" " lib9,\n" " lib10,\n" " lib11,\n" " lib12,\n" " lib13,\n" " lib14,\n" " lib15,\n" " lib16,\n" " lib17,\n" " lib18,\n" " lib20,\n" " lib21,\n" " lib22)\n" ) test_output_hanging_indent = isort.code( code=REALLY_LONG_IMPORT, multi_line_output=WrapModes.HANGING_INDENT, line_length=40, indent=" ", ) assert test_output_hanging_indent == ( "from third_party import lib1, lib2, \\\n" " lib3, lib4, lib5, lib6, lib7, \\\n" " lib8, lib9, lib10, lib11, lib12, \\\n" " lib13, lib14, lib15, lib16, lib17, \\\n" " lib18, lib20, lib21, lib22\n" ) comment_output_hanging_indent = isort.code( code=REALLY_LONG_IMPORT_WITH_COMMENT, multi_line_output=WrapModes.HANGING_INDENT, line_length=40, indent=" ", ) assert comment_output_hanging_indent == ( "from third_party import lib1, lib2, \\\n" " lib3, lib4, lib5, lib6, lib7, \\\n" " lib8, lib9, lib10, lib11, lib12, \\\n" " lib13, lib14, lib15, lib16, lib17, \\\n" " lib18, lib20, lib21, lib22 \\\n" " # comment\n" ) test_output_vertical_indent = isort.code( code=REALLY_LONG_IMPORT, multi_line_output=WrapModes.VERTICAL_HANGING_INDENT, line_length=40, indent=" ", ) assert test_output_vertical_indent == ( "from third_party import (\n" " lib1,\n" " lib2,\n" " lib3,\n" " lib4,\n" " lib5,\n" " lib6,\n" " lib7,\n" " lib8,\n" " lib9,\n" " lib10,\n" " lib11,\n" " lib12,\n" " lib13,\n" " lib14,\n" " lib15,\n" " lib16,\n" " lib17,\n" " lib18,\n" " lib20,\n" " lib21,\n" " lib22\n" ")\n" ) comment_output_vertical_indent = isort.code( code=REALLY_LONG_IMPORT_WITH_COMMENT, multi_line_output=WrapModes.VERTICAL_HANGING_INDENT, line_length=40, indent=" ", ) assert comment_output_vertical_indent == ( "from third_party import ( # comment\n" " lib1,\n" " lib2,\n" " lib3,\n" " lib4,\n" " lib5,\n" " lib6,\n" " lib7,\n" " lib8,\n" " lib9,\n" " lib10,\n" " lib11,\n" " lib12,\n" " lib13,\n" " lib14,\n" " lib15,\n" " lib16,\n" " lib17,\n" " lib18,\n" " lib20,\n" " lib21,\n" " lib22\n" ")\n" ) test_output_vertical_grid = isort.code( code=REALLY_LONG_IMPORT, multi_line_output=WrapModes.VERTICAL_GRID, line_length=40, indent=" ", ) assert test_output_vertical_grid == ( "from third_party import (\n" " lib1, lib2, lib3, lib4, lib5, lib6,\n" " lib7, lib8, lib9, lib10, lib11,\n" " lib12, lib13, lib14, lib15, lib16,\n" " lib17, lib18, lib20, lib21, lib22)\n" ) comment_output_vertical_grid = isort.code( code=REALLY_LONG_IMPORT_WITH_COMMENT, multi_line_output=WrapModes.VERTICAL_GRID, line_length=40, indent=" ", ) assert comment_output_vertical_grid == ( "from third_party import ( # comment\n" " lib1, lib2, lib3, lib4, lib5, lib6,\n" " lib7, lib8, lib9, lib10, lib11,\n" " lib12, lib13, lib14, lib15, lib16,\n" " lib17, lib18, lib20, lib21, lib22)\n" ) test_output_vertical_grid_grouped = isort.code( code=REALLY_LONG_IMPORT, multi_line_output=WrapModes.VERTICAL_GRID_GROUPED, line_length=40, indent=" ", ) assert test_output_vertical_grid_grouped == ( "from third_party import (\n" " lib1, lib2, lib3, lib4, lib5, lib6,\n" " lib7, lib8, lib9, lib10, lib11,\n" " lib12, lib13, lib14, lib15, lib16,\n" " lib17, lib18, lib20, lib21, lib22\n" ")\n" ) comment_output_vertical_grid_grouped = isort.code( code=REALLY_LONG_IMPORT_WITH_COMMENT, multi_line_output=WrapModes.VERTICAL_GRID_GROUPED, line_length=40, indent=" ", ) assert comment_output_vertical_grid_grouped == ( "from third_party import ( # comment\n" " lib1, lib2, lib3, lib4, lib5, lib6,\n" " lib7, lib8, lib9, lib10, lib11,\n" " lib12, lib13, lib14, lib15, lib16,\n" " lib17, lib18, lib20, lib21, lib22\n" ")\n" ) output_noqa = isort.code(code=REALLY_LONG_IMPORT_WITH_COMMENT, multi_line_output=WrapModes.NOQA) assert output_noqa == ( "from third_party import lib1, lib2, lib3, lib4, lib5, lib6, lib7," " lib8, lib9, lib10, lib11," " lib12, lib13, lib14, lib15, lib16, lib17, lib18, lib20, lib21, lib22 " "# NOQA comment\n" ) test_case = isort.code( code=SINGLE_LINE_LONG_IMPORT, multi_line_output=WrapModes.VERTICAL_GRID_GROUPED, line_length=40, indent=" ", ) test_output_vertical_grid_grouped_doesnt_wrap_early = test_case assert test_output_vertical_grid_grouped_doesnt_wrap_early == ( "from third_party import (\n lib1, lib2, lib3, lib4, lib5, lib5ab\n)\n" ) test_output_prefix_from_module = isort.code( code=REALLY_LONG_IMPORT, multi_line_output=WrapModes.VERTICAL_PREFIX_FROM_MODULE_IMPORT, line_length=40, ) assert test_output_prefix_from_module == ( "from third_party import lib1, lib2\n" "from third_party import lib3, lib4\n" "from third_party import lib5, lib6\n" "from third_party import lib7, lib8\n" "from third_party import lib9, lib10\n" "from third_party import lib11, lib12\n" "from third_party import lib13, lib14\n" "from third_party import lib15, lib16\n" "from third_party import lib17, lib18\n" "from third_party import lib20, lib21\n" "from third_party import lib22\n" ) test_output_prefix_from_module_with_comment = isort.code( code=REALLY_LONG_IMPORT_WITH_COMMENT, multi_line_output=WrapModes.VERTICAL_PREFIX_FROM_MODULE_IMPORT, line_length=40, indent=" ", ) assert test_output_prefix_from_module_with_comment == ( "from third_party import lib1 # comment\n" "from third_party import lib2, lib3\n" "from third_party import lib4, lib5\n" "from third_party import lib6, lib7\n" "from third_party import lib8, lib9\n" "from third_party import lib10, lib11\n" "from third_party import lib12, lib13\n" "from third_party import lib14, lib15\n" "from third_party import lib16, lib17\n" "from third_party import lib18, lib20\n" "from third_party import lib21, lib22\n" ) test_output_hanging_indent_with_parentheses = isort.code( code=REALLY_LONG_IMPORT, multi_line_output=WrapModes.HANGING_INDENT_WITH_PARENTHESES, line_length=40, indent=" ", ) assert test_output_hanging_indent_with_parentheses == ( "from third_party import (lib1, lib2,\n" " lib3, lib4, lib5, lib6, lib7, lib8,\n" " lib9, lib10, lib11, lib12, lib13,\n" " lib14, lib15, lib16, lib17, lib18,\n" " lib20, lib21, lib22)\n" ) comment_output_hanging_indent_with_parentheses = isort.code( code=REALLY_LONG_IMPORT_WITH_COMMENT, multi_line_output=WrapModes.HANGING_INDENT_WITH_PARENTHESES, line_length=40, indent=" ", ) assert comment_output_hanging_indent_with_parentheses == ( "from third_party import (lib1, # comment\n" " lib2, lib3, lib4, lib5, lib6, lib7,\n" " lib8, lib9, lib10, lib11, lib12,\n" " lib13, lib14, lib15, lib16, lib17,\n" " lib18, lib20, lib21, lib22)\n" ) test_input = ( "def a():\n" " from allennlp.modules.text_field_embedders.basic_text_field_embedder" " import BasicTextFieldEmbedder" ) test_output = isort.code(test_input, line_length=100) assert test_output == ( "def a():\n" " from allennlp.modules.text_field_embedders.basic_text_field_embedder import \\\n" " BasicTextFieldEmbedder" ) test_input = ( "class A:\n" " def a():\n" " from allennlp.common.registrable import Registrable" " # import here to avoid circular imports\n" "\n\n" "class B:\n" " def b():\n" " from allennlp.common.registrable import Registrable" " # import here to avoid circular imports\n" ) test_output = isort.code(test_input, line_length=100) assert test_output == test_input def test_qa_comment_case() -> None: test_input = "from veryveryveryveryveryveryveryveryveryveryvery import X # NOQA" test_output = isort.code(code=test_input, line_length=40, multi_line_output=WrapModes.NOQA) assert test_output == "from veryveryveryveryveryveryveryveryveryveryvery import X # NOQA\n" test_input = "import veryveryveryveryveryveryveryveryveryveryvery # NOQA" test_output = isort.code(code=test_input, line_length=40, multi_line_output=WrapModes.NOQA) assert test_output == "import veryveryveryveryveryveryveryveryveryveryvery # NOQA\n" def test_length_sort() -> None: """Test setting isort to sort on length instead of alphabetically.""" test_input = ( "import medium_sizeeeeeeeeeeeeee\n" "import shortie\n" "import looooooooooooooooooooooooooooooooooooooong\n" "import medium_sizeeeeeeeeeeeeea\n" ) test_output = isort.code(test_input, length_sort=True) assert test_output == ( "import shortie\n" "import medium_sizeeeeeeeeeeeeea\n" "import medium_sizeeeeeeeeeeeeee\n" "import looooooooooooooooooooooooooooooooooooooong\n" ) def test_length_sort_straight() -> None: """Test setting isort to sort straight imports on length instead of alphabetically.""" test_input = ( "import medium_sizeeeeeeeeeeeeee\n" "import shortie\n" "import looooooooooooooooooooooooooooooooooooooong\n" "from medium_sizeeeeeeeeeeeeee import b\n" "from shortie import c\n" "from looooooooooooooooooooooooooooooooooooooong import a\n" ) test_output = isort.code(test_input, length_sort_straight=True) assert test_output == ( "import shortie\n" "import medium_sizeeeeeeeeeeeeee\n" "import looooooooooooooooooooooooooooooooooooooong\n" "from looooooooooooooooooooooooooooooooooooooong import a\n" "from medium_sizeeeeeeeeeeeeee import b\n" "from shortie import c\n" ) def test_length_sort_section() -> None: """Test setting isort to sort on length instead of alphabetically for a specific section.""" test_input = ( "import medium_sizeeeeeeeeeeeeee\n" "import shortie\n" "import datetime\n" "import sys\n" "import os\n" "import looooooooooooooooooooooooooooooooooooooong\n" "import medium_sizeeeeeeeeeeeeea\n" ) test_output = isort.code(test_input, length_sort_sections=("stdlib",)) assert test_output == ( "import os\n" "import sys\n" "import datetime\n" "\n" "import looooooooooooooooooooooooooooooooooooooong\n" "import medium_sizeeeeeeeeeeeeea\n" "import medium_sizeeeeeeeeeeeeee\n" "import shortie\n" ) def test_convert_hanging() -> None: """Ensure that isort will convert hanging indents to correct indent method.""" test_input = ( "from third_party import lib1, lib2, \\\n" " lib3, lib4, lib5, lib6, lib7, \\\n" " lib8, lib9, lib10, lib11, lib12, \\\n" " lib13, lib14, lib15, lib16, lib17, \\\n" " lib18, lib20, lib21, lib22\n" ) test_output = isort.code(code=test_input, multi_line_output=WrapModes.GRID, line_length=40) assert test_output == ( "from third_party import (lib1, lib2,\n" " lib3, lib4,\n" " lib5, lib6,\n" " lib7, lib8,\n" " lib9, lib10,\n" " lib11, lib12,\n" " lib13, lib14,\n" " lib15, lib16,\n" " lib17, lib18,\n" " lib20, lib21,\n" " lib22)\n" ) def test_custom_indent() -> None: """Ensure setting a custom indent will work as expected.""" test_output = isort.code( code=REALLY_LONG_IMPORT, multi_line_output=WrapModes.HANGING_INDENT, line_length=40, indent=" ", balanced_wrapping=False, ) assert test_output == ( "from third_party import lib1, lib2, \\\n" " lib3, lib4, lib5, lib6, lib7, lib8, \\\n" " lib9, lib10, lib11, lib12, lib13, \\\n" " lib14, lib15, lib16, lib17, lib18, \\\n" " lib20, lib21, lib22\n" ) test_output = isort.code( code=REALLY_LONG_IMPORT, multi_line_output=WrapModes.HANGING_INDENT, line_length=40, indent="' '", balanced_wrapping=False, ) assert test_output == ( "from third_party import lib1, lib2, \\\n" " lib3, lib4, lib5, lib6, lib7, lib8, \\\n" " lib9, lib10, lib11, lib12, lib13, \\\n" " lib14, lib15, lib16, lib17, lib18, \\\n" " lib20, lib21, lib22\n" ) test_output = isort.code( code=REALLY_LONG_IMPORT, multi_line_output=WrapModes.HANGING_INDENT, line_length=40, indent="tab", balanced_wrapping=False, ) assert test_output == ( "from third_party import lib1, lib2, \\\n" "\tlib3, lib4, lib5, lib6, lib7, lib8, \\\n" "\tlib9, lib10, lib11, lib12, lib13, \\\n" "\tlib14, lib15, lib16, lib17, lib18, \\\n" "\tlib20, lib21, lib22\n" ) test_output = isort.code( code=REALLY_LONG_IMPORT, multi_line_output=WrapModes.HANGING_INDENT, line_length=40, indent=2, balanced_wrapping=False, ) assert test_output == ( "from third_party import lib1, lib2, \\\n" " lib3, lib4, lib5, lib6, lib7, lib8, \\\n" " lib9, lib10, lib11, lib12, lib13, \\\n" " lib14, lib15, lib16, lib17, lib18, \\\n" " lib20, lib21, lib22\n" ) def test_use_parentheses() -> None: test_input = ( "from fooooooooooooooooooooooooo.baaaaaaaaaaaaaaaaaaarrrrrrr import " " my_custom_function as my_special_function" ) test_output = isort.code(test_input, line_length=79, use_parentheses=True) assert test_output == ( "from fooooooooooooooooooooooooo.baaaaaaaaaaaaaaaaaaarrrrrrr import (\n" " my_custom_function as my_special_function)\n" ) test_output = isort.code( code=test_input, line_length=79, use_parentheses=True, include_trailing_comma=True ) assert test_output == ( "from fooooooooooooooooooooooooo.baaaaaaaaaaaaaaaaaaarrrrrrr import (\n" " my_custom_function as my_special_function,)\n" ) test_output = isort.code( code=test_input, line_length=79, use_parentheses=True, multi_line_output=WrapModes.VERTICAL_HANGING_INDENT, ) assert test_output == ( "from fooooooooooooooooooooooooo.baaaaaaaaaaaaaaaaaaarrrrrrr import (\n" " my_custom_function as my_special_function\n)\n" ) test_output = isort.code( code=test_input, line_length=79, use_parentheses=True, multi_line_output=WrapModes.VERTICAL_GRID_GROUPED, include_trailing_comma=True, ) assert test_output == ( "from fooooooooooooooooooooooooo.baaaaaaaaaaaaaaaaaaarrrrrrr import (\n" " my_custom_function as my_special_function,\n)\n" ) def test_skip() -> None: """Ensure skipping a single import will work as expected.""" test_input = ( "import myproject\n" "import django\n" "print('hey')\n" "import sys # isort: skip this import needs to be placed here\n\n\n\n\n\n\n" ) test_output = isort.code(test_input, known_first_party=["myproject"]) assert test_output == ( "import django\n" "\n" "import myproject\n" "\n" "print('hey')\n" "import sys # isort: skip this import needs to be placed here\n" ) def test_skip_with_file_name() -> None: """Ensure skipping a file works even when file_contents is provided.""" test_input = "import django\nimport myproject\n" with pytest.raises(FileSkipped): isort.code( file_path=Path("/baz.py"), code=test_input, settings_path=os.getcwd(), skip=["baz.py"] ) def test_skip_within_file() -> None: """Ensure skipping a whole file works.""" test_input = "# isort: skip_file\nimport django\nimport myproject\n" with pytest.raises(FileSkipped): isort.code(test_input, known_third_party=["django"]) def test_force_to_top() -> None: """Ensure forcing a single import to the top of its category works as expected.""" test_input = "import lib6\nimport lib2\nimport lib5\nimport lib1\n" test_output = isort.code(test_input, force_to_top=["lib5"]) assert test_output == "import lib5\nimport lib1\nimport lib2\nimport lib6\n" def test_add_imports() -> None: """Ensures adding imports works as expected.""" test_input = "import lib6\nimport lib2\nimport lib5\nimport lib1\n\n" test_output = isort.code(code=test_input, add_imports=["import lib4", "import lib7"]) assert test_output == ( "import lib1\n" "import lib2\n" "import lib4\n" "import lib5\n" "import lib6\n" "import lib7\n" ) # Using simplified syntax test_input = "import lib6\nimport lib2\nimport lib5\nimport lib1\n\n" test_output = isort.code(code=test_input, add_imports=["lib4", "lib7", "lib8.a"]) assert test_output == ( "import lib1\n" "import lib2\n" "import lib4\n" "import lib5\n" "import lib6\n" "import lib7\n" "from lib8 import a\n" ) # On a file that has no pre-existing imports test_input = '"""Module docstring"""\n' "class MyClass(object):\n pass\n" test_output = isort.code(code=test_input, add_imports=["from __future__ import print_function"]) assert test_output == ( '"""Module docstring"""\n' "from __future__ import print_function\n" "\n" "\n" "class MyClass(object):\n" " pass\n" ) # On a file that has no pre-existing imports and a multiline docstring test_input = ( '"""Module docstring\n\nWith a second line\n"""\n' "class MyClass(object):\n pass\n" ) test_output = isort.code(code=test_input, add_imports=["from __future__ import print_function"]) assert test_output == ( '"""Module docstring\n' "\n" "With a second line\n" '"""\n' "from __future__ import print_function\n" "\n" "\n" "class MyClass(object):\n" " pass\n" ) # On a file that has no pre-existing imports and a multiline docstring. # In this example, the closing quotes for the docstring are on the final # line rather than a separate one. test_input = ( '"""Module docstring\n\nWith a second line"""\n' "class MyClass(object):\n pass\n" ) test_output = isort.code(code=test_input, add_imports=["from __future__ import print_function"]) assert test_output == ( '"""Module docstring\n' "\n" 'With a second line"""\n' "from __future__ import print_function\n" "\n" "\n" "class MyClass(object):\n" " pass\n" ) # On a file that has no pre-existing imports, and no doc-string test_input = "class MyClass(object):\n pass\n" test_output = isort.code(code=test_input, add_imports=["from __future__ import print_function"]) assert test_output == ( "from __future__ import print_function\n" "\n" "\n" "class MyClass(object):\n" " pass\n" ) # On a file with no content what so ever test_input = "" test_output = isort.code(test_input, add_imports=["lib4"]) assert test_output == ("") # On a file with no content what so ever, after force_adds is set to True test_input = "" test_output = isort.code(code=test_input, add_imports=["lib4"], force_adds=True) assert test_output == ("import lib4\n") def test_remove_imports() -> None: """Ensures removing imports works as expected.""" test_input = "import lib6\nimport lib2\nimport lib5\nimport lib1" test_output = isort.code(test_input, remove_imports=["lib2", "lib6"]) assert test_output == "import lib1\nimport lib5\n" # Using natural syntax test_input = ( "import lib6\n" "import lib2\n" "import lib5\n" "import lib1\n" "from lib8 import a" ) test_output = isort.code( code=test_input, remove_imports=["import lib2", "import lib6", "from lib8 import a"] ) assert test_output == "import lib1\nimport lib5\n" # From imports test_input = "from x import y" test_output = isort.code(test_input, remove_imports=["x"]) assert test_output == "" test_input = "from x import y" test_output = isort.code(test_input, remove_imports=["x.y"]) assert test_output == "" def test_comments_above(): """Test to ensure comments above an import will stay in place""" test_input = "import os\n\nfrom x import y\n\n# comment\nfrom z import __version__, api\n" assert isort.code(test_input, ensure_newline_before_comments=True) == test_input def test_explicitly_local_import() -> None: """Ensure that explicitly local imports are separated.""" test_input = "import lib1\nimport lib2\nimport .lib6\nfrom . import lib7" assert isort.code(test_input) == ( "import lib1\nimport lib2\n\nimport .lib6\nfrom . import lib7\n" ) assert isort.code(test_input, old_finders=True) == ( "import lib1\nimport lib2\n\nimport .lib6\nfrom . import lib7\n" ) def test_quotes_in_file() -> None: """Ensure imports within triple quotes don't get imported.""" test_input = "import os\n\n" '"""\n' "Let us\nimport foo\nokay?\n" '"""\n' assert isort.code(test_input) == test_input test_input = "import os\n\n" '\'"""\'\n' "import foo\n" assert isort.code(test_input) == test_input test_input = "import os\n\n" '"""Let us"""\n' "import foo\n\n" '"""okay?"""\n' assert isort.code(test_input) == test_input test_input = "import os\n\n" '#"""\n' "import foo\n" '#"""' assert isort.code(test_input) == ('import os\n\nimport foo\n\n#"""\n#"""\n') test_input = "import os\n\n'\\\nimport foo'\n" assert isort.code(test_input) == test_input test_input = "import os\n\n'''\n\\'''\nimport junk\n'''\n" assert isort.code(test_input) == test_input def test_check_newline_in_imports(capsys) -> None: """Ensure tests works correctly when new lines are in imports.""" test_input = "from lib1 import (\n sub1,\n sub2,\n sub3\n)\n" assert api.check_code_string( code=test_input, multi_line_output=WrapModes.VERTICAL_HANGING_INDENT, line_length=20, verbose=True, ) out, _ = capsys.readouterr() assert "SUCCESS" in out # if the verbose is only on modified outputs no output will be given assert api.check_code_string( code=test_input, multi_line_output=WrapModes.VERTICAL_HANGING_INDENT, line_length=20, verbose=True, only_modified=True, ) out, _ = capsys.readouterr() assert not out # we can make the input invalid to again see output test_input = "from lib1 import (\n sub2,\n sub1,\n sub3\n)\n" assert not api.check_code_string( code=test_input, multi_line_output=WrapModes.VERTICAL_HANGING_INDENT, line_length=20, verbose=True, only_modified=True, ) out, _ = capsys.readouterr() assert out def test_forced_separate() -> None: """Ensure that forcing certain sub modules to show separately works as expected.""" test_input = ( "import sys\n" "import warnings\n" "from collections import OrderedDict\n" "\n" "from django.core.exceptions import ImproperlyConfigured, SuspiciousOperation\n" "from django.core.paginator import InvalidPage\n" "from django.core.urlresolvers import reverse\n" "from django.db import models\n" "from django.db.models.fields import FieldDoesNotExist\n" "from django.utils import six\n" "\n" "from django.utils.deprecation import RenameMethodsBase\n" "from django.utils.encoding import force_str, force_text\n" "from django.utils.http import urlencode\n" "from django.utils.translation import ugettext, ugettext_lazy\n" "\n" "from django.contrib.admin import FieldListFilter\n" "from django.contrib.admin.exceptions import DisallowedModelAdminLookup\n" "from django.contrib.admin.options import IncorrectLookupParameters, IS_POPUP_VAR, " "TO_FIELD_VAR\n" ) assert ( isort.code( code=test_input, forced_separate=["django.utils.*", "django.contrib"], known_third_party=["django"], line_length=120, order_by_type=False, ) == test_input ) assert ( isort.code( code=test_input, forced_separate=["django.utils.*", "django.contrib"], known_third_party=["django"], line_length=120, order_by_type=False, old_finders=True, ) == test_input ) test_input = "from .foo import bar\n\nfrom .y import ca\n" assert ( isort.code(code=test_input, forced_separate=[".y"], line_length=120, order_by_type=False) == test_input ) assert ( isort.code( code=test_input, forced_separate=[".y"], line_length=120, order_by_type=False, old_finders=True, ) == test_input ) def test_default_section() -> None: """Test to ensure changing the default section works as expected.""" test_input = "import sys\nimport os\nimport myproject.test\nimport django.settings" test_output = isort.code( code=test_input, known_third_party=["django"], default_section="FIRSTPARTY" ) assert test_output == ( "import os\n" "import sys\n" "\n" "import django.settings\n" "\n" "import myproject.test\n" ) test_output_custom = isort.code( code=test_input, known_third_party=["django"], default_section="STDLIB" ) assert test_output_custom == ( "import myproject.test\n" "import os\n" "import sys\n" "\n" "import django.settings\n" ) def test_first_party_overrides_standard_section() -> None: """Test to ensure changing the default section works as expected.""" test_input = ( "from HTMLParser import HTMLParseError, HTMLParser\n" "import sys\n" "import os\n" "import profile.test\n" ) test_output = isort.code(code=test_input, known_first_party=["profile"], py_version="27") assert test_output == ( "import os\n" "import sys\n" "from HTMLParser import HTMLParseError, HTMLParser\n" "\n" "import profile.test\n" ) def test_thirdy_party_overrides_standard_section() -> None: """Test to ensure changing the default section works as expected.""" test_input = "import sys\nimport os\nimport profile.test\n" test_output = isort.code(test_input, known_third_party=["profile"]) assert test_output == "import os\nimport sys\n\nimport profile.test\n" def test_known_pattern_path_expansion(tmpdir) -> None: """Test to ensure patterns ending with path sep gets expanded and nested packages treated as known patterns. """ src_dir = tmpdir.mkdir("src") src_dir.mkdir("foo") src_dir.mkdir("bar") test_input = ( "from kate_plugin import isort_plugin\n" "import sys\n" "from foo import settings\n" "import bar\n" "import this\n" "import os\n" ) test_output = isort.code( code=test_input, default_section="THIRDPARTY", known_first_party=["src/", "this", "kate_plugin"], directory=str(tmpdir), ) test_output_old_finder = isort.code( code=test_input, default_section="FIRSTPARTY", old_finders=True, known_first_party=["src/", "this", "kate_plugin"], directory=str(tmpdir), ) assert ( test_output_old_finder == test_output == ( "import os\n" "import sys\n" "\n" "import bar\n" "import this\n" "from foo import settings\n" "from kate_plugin import isort_plugin\n" ) ) def test_force_single_line_imports() -> None: """Test to ensure forcing imports to each have their own line works as expected.""" test_input = ( "from third_party import lib1, lib2, \\\n" " lib3, lib4, lib5, lib6, lib7, \\\n" " lib8, lib9, lib10, lib11, lib12, \\\n" " lib13, lib14, lib15, lib16, lib17, \\\n" " lib18, lib20, lib21, lib22\n" ) test_output = isort.code( code=test_input, multi_line_output=WrapModes.GRID, line_length=40, force_single_line=True ) assert test_output == ( "from third_party import lib1\n" "from third_party import lib2\n" "from third_party import lib3\n" "from third_party import lib4\n" "from third_party import lib5\n" "from third_party import lib6\n" "from third_party import lib7\n" "from third_party import lib8\n" "from third_party import lib9\n" "from third_party import lib10\n" "from third_party import lib11\n" "from third_party import lib12\n" "from third_party import lib13\n" "from third_party import lib14\n" "from third_party import lib15\n" "from third_party import lib16\n" "from third_party import lib17\n" "from third_party import lib18\n" "from third_party import lib20\n" "from third_party import lib21\n" "from third_party import lib22\n" ) test_input = ( "from third_party import lib_a, lib_b, lib_d\n" "from third_party.lib_c import lib1\n" ) test_output = isort.code( code=test_input, multi_line_output=WrapModes.GRID, line_length=40, force_single_line=True ) assert test_output == ( "from third_party import lib_a\n" "from third_party import lib_b\n" "from third_party import lib_d\n" "from third_party.lib_c import lib1\n" ) def test_force_single_line_long_imports() -> None: test_input = "from veryveryveryveryveryvery import small, big\n" test_output = isort.code( code=test_input, multi_line_output=WrapModes.NOQA, line_length=40, force_single_line=True ) assert test_output == ( "from veryveryveryveryveryvery import big\n" "from veryveryveryveryveryvery import small # NOQA\n" ) def test_force_single_line_imports_and_sort_within_sections() -> None: test_input = ( "from third_party import lib_a, lib_b, lib_d\n" "from third_party.lib_c import lib1\n" ) test_output = isort.code( code=test_input, multi_line_output=WrapModes.GRID, line_length=40, force_single_line=True, force_sort_within_sections=True, ) assert test_output == ( "from third_party import lib_a\n" "from third_party import lib_b\n" "from third_party import lib_d\n" "from third_party.lib_c import lib1\n" ) test_output = isort.code( code=test_input, multi_line_output=WrapModes.GRID, line_length=40, force_single_line=True, force_sort_within_sections=True, lexicographical=True, ) assert test_output == ( "from third_party import lib_a\n" "from third_party import lib_b\n" "from third_party.lib_c import lib1\n" "from third_party import lib_d\n" ) test_input = """import sympy import numpy as np import pandas as pd from matplotlib import pyplot as plt """ assert ( isort.code(code=test_input, force_sort_within_sections=True, length_sort=True) == test_input ) def test_titled_imports() -> None: """Tests setting custom titled/commented import sections.""" test_input = ( "import sys\n" "import unicodedata\n" "import statistics\n" "import os\n" "import myproject.test\n" "import django.settings" ) test_output = isort.code( code=test_input, known_first_party=["myproject"], import_heading_stdlib="Standard Library", import_heading_firstparty="My Stuff", ) assert test_output == ( "# Standard Library\n" "import os\n" "import statistics\n" "import sys\n" "import unicodedata\n" "\n" "import django.settings\n" "\n" "# My Stuff\n" "import myproject.test\n" ) test_second_run = isort.code( code=test_output, known_first_party=["myproject"], import_heading_stdlib="Standard Library", import_heading_firstparty="My Stuff", ) assert test_second_run == test_output test_input_lines_down = ( "# comment 1\n" "import django.settings\n" "\n" "# Standard Library\n" "import sys\n" "import unicodedata\n" "import statistics\n" "import os\n" "import myproject.test\n" ) test_output_lines_down = isort.code( code=test_input_lines_down, known_first_party=["myproject"], import_heading_stdlib="Standard Library", import_heading_firstparty="My Stuff", ) assert test_output_lines_down == ( "# comment 1\n" "# Standard Library\n" "import os\n" "import statistics\n" "import sys\n" "import unicodedata\n" "\n" "import django.settings\n" "\n" "# My Stuff\n" "import myproject.test\n" ) def test_footered_imports() -> None: """Tests setting both custom titles and footers to import sections.""" test_input = ( "import sys\n" "import unicodedata\n" "import statistics\n" "import os\n" "import myproject.test\n" "import django.settings" ) test_output = isort.code( code=test_input, known_first_party=["myproject"], import_footer_stdlib="Standard Library End", import_footer_firstparty="My Stuff End", ) assert test_output == ( "import os\n" "import statistics\n" "import sys\n" "import unicodedata\n" "\n" "# Standard Library End\n" "\n" "import django.settings\n" "\n" "import myproject.test\n" "\n" "# My Stuff End\n" ) test_second_run = isort.code( code=test_output, known_first_party=["myproject"], import_footer_stdlib="Standard Library End", import_footer_firstparty="My Stuff End", ) assert test_second_run == test_output test_input_lines_down = ( "# comment 1\n" "import django.settings\n" "\n" "import sys\n" "import unicodedata\n" "import statistics\n" "import os\n" "import myproject.test\n" "\n" "# Standard Library End\n" ) test_output_lines_down = isort.code( code=test_input_lines_down, known_first_party=["myproject"], import_footer_stdlib="Standard Library End", import_footer_firstparty="My Stuff End", ) assert test_output_lines_down == ( "# comment 1\n" "import os\n" "import statistics\n" "import sys\n" "import unicodedata\n" "\n" "# Standard Library End\n" "\n" "import django.settings\n" "\n" "import myproject.test\n" "\n" "# My Stuff End\n" ) def test_titled_and_footered_imports() -> None: """Tests setting custom footers to import sections.""" test_input = ( "import sys\n" "import unicodedata\n" "import statistics\n" "import os\n" "import myproject.test\n" "import django.settings" ) test_output = isort.code( code=test_input, known_first_party=["myproject"], import_heading_stdlib="Standard Library", import_heading_firstparty="My Stuff", import_footer_stdlib="Standard Library End", import_footer_firstparty="My Stuff End", ) assert test_output == ( "# Standard Library\n" "import os\n" "import statistics\n" "import sys\n" "import unicodedata\n" "\n" "# Standard Library End\n" "\n" "import django.settings\n" "\n" "# My Stuff\n" "import myproject.test\n" "\n" "# My Stuff End\n" ) test_second_run = isort.code( code=test_output, known_first_party=["myproject"], import_heading_stdlib="Standard Library", import_heading_firstparty="My Stuff", import_footer_stdlib="Standard Library End", import_footer_firstparty="My Stuff End", ) assert test_second_run == test_output test_input_lines_down = ( "# comment 1\n" "import django.settings\n" "\n" "# Standard Library\n" "import sys\n" "import unicodedata\n" "import statistics\n" "import os\n" "import myproject.test\n" "\n" "# Standard Library End\n" ) test_output_lines_down = isort.code( code=test_input_lines_down, known_first_party=["myproject"], import_heading_stdlib="Standard Library", import_heading_firstparty="My Stuff", import_footer_stdlib="Standard Library End", import_footer_firstparty="My Stuff End", ) assert test_output_lines_down == ( "# comment 1\n" "# Standard Library\n" "import os\n" "import statistics\n" "import sys\n" "import unicodedata\n" "\n" "# Standard Library End\n" "\n" "import django.settings\n" "\n" "# My Stuff\n" "import myproject.test\n" "\n" "# My Stuff End\n" ) test_input_lines_down = ( "# comment 1\n" "import django.settings\n" "\n" "# Standard Library\n" "import sys\n" "import unicodedata\n" "import statistics\n" "import os\n" "import myproject.test\n" "\n" "# Standard Library End\n" "# Standard Library End\n" ) test_output_lines_down = isort.code( code=test_input_lines_down, known_first_party=["myproject"], import_heading_stdlib="Standard Library", import_heading_firstparty="My Stuff", import_footer_stdlib="Standard Library End", import_footer_firstparty="My Stuff End", dedup_headings=True, ) assert test_output_lines_down == ( "# comment 1\n" "# Standard Library\n" "import os\n" "import statistics\n" "import sys\n" "import unicodedata\n" "\n" "# Standard Library End\n" "\n" "import django.settings\n" "\n" "# My Stuff\n" "import myproject.test\n" "\n" "# My Stuff End\n" ) test_input_lines_down = ( "# comment 1\n" "# Standard Library\n" "import os\n" "import statistics\n" "import sys\n" "import unicodedata\n" "\n" "# Standard Library End\n" "\n" "import django.settings\n" "\n" "# My Stuff\n" "import myproject.test\n" ) test_output_lines_down = isort.code( code=test_input_lines_down, known_first_party=["myproject"], import_heading_stdlib="Standard Library", import_heading_firstparty="My Stuff", import_footer_stdlib="Standard Library End", import_footer_firstparty="My Stuff End", dedup_headings=True, ) assert test_output_lines_down == ( "# comment 1\n" "# Standard Library\n" "import os\n" "import statistics\n" "import sys\n" "import unicodedata\n" "\n" "# Standard Library End\n" "\n" "import django.settings\n" "\n" "# My Stuff\n" "import myproject.test\n" "\n" "# My Stuff End\n" ) def test_balanced_wrapping() -> None: """Tests balanced wrapping mode, where the length of individual lines maintain width.""" test_input = ( "from __future__ import (absolute_import, division, print_function,\n" " unicode_literals)" ) test_output = isort.code(code=test_input, line_length=70, balanced_wrapping=True) assert test_output == ( "from __future__ import (absolute_import, division,\n" " print_function, unicode_literals)\n" ) def test_relative_import_with_space() -> None: """Tests the case where the relation and the module that is being imported from is separated with a space. """ test_input = "from ... fields.sproqet import SproqetCollection" assert isort.code(test_input) == ("from ...fields.sproqet import SproqetCollection\n") test_input = "from .import foo" test_output = "from . import foo\n" assert isort.code(test_input) == test_output test_input = "from.import foo" test_output = "from . import foo\n" assert isort.code(test_input) == test_output def test_multiline_import() -> None: """Test the case where import spawns multiple lines with inconsistent indentation.""" test_input = "from pkg \\\n import stuff, other_suff \\\n more_stuff" assert isort.code(test_input) == ("from pkg import more_stuff, other_suff, stuff\n") # test again with a custom configuration custom_configuration: dict[str, Any] = { "force_single_line": True, "line_length": 120, "known_first_party": ["asdf", "qwer"], "default_section": "THIRDPARTY", "forced_separate": "asdf", } expected_output = ( "from pkg import more_stuff\n" "from pkg import other_suff\n" "from pkg import stuff\n" ) assert isort.code(test_input, **custom_configuration) == expected_output def test_single_multiline() -> None: """Test the case where a single import spawns multiple lines.""" test_input = "from os import\\\n getuid\n\nprint getuid()\n" output = isort.code(test_input) assert output == ("from os import getuid\n\nprint getuid()\n") def test_atomic_mode() -> None: """With atomic mode isort should be able to automatically detect and stop syntax errors""" # without syntax error, everything works OK test_input = "from b import d, c\nfrom a import f, e\n" assert isort.code(test_input, atomic=True) == ("from a import e, f\nfrom b import c, d\n") # with syntax error content is not changed test_input += "while True print 'Hello world'" # blatant syntax error with pytest.raises(ExistingSyntaxErrors): isort.code(test_input, atomic=True) # unless file is for Cython which doesn't yet provide a public AST parsing API assert ( isort.code(test_input, extension="pyx", atomic=True, verbose=True) == isort.code(test_input, extension="pyx", atomic=True) == """from a import e, f from b import c, d while True print 'Hello world' """ ) # ensure atomic works with streams test_stream_input = as_stream("from b import d, c\nfrom a import f, e\n") test_output = UnreadableStream() isort.stream(test_stream_input, test_output, atomic=True) test_output.seek(0) assert test_output.read() == "from a import e, f\nfrom b import c, d\n" def test_order_by_type() -> None: test_input = "from module import Class, CONSTANT, function" assert isort.code(test_input, order_by_type=True) == ( "from module import CONSTANT, Class, function\n" ) # More complex sample data test_input = "from module import Class, CONSTANT, function, BASIC, Apple" assert isort.code(test_input, order_by_type=True) == ( "from module import BASIC, CONSTANT, Apple, Class, function\n" ) # Really complex sample data, to verify we don't mess with top level imports, only nested ones test_input = ( "import StringIO\n" "import glob\n" "import os\n" "import shutil\n" "import tempfile\n" "import time\n" "from subprocess import PIPE, Popen, STDOUT\n" ) assert isort.code(test_input, order_by_type=True, py_version="27") == ( "import glob\n" "import os\n" "import shutil\n" "import StringIO\n" "import tempfile\n" "import time\n" "from subprocess import PIPE, STDOUT, Popen\n" ) def test_custom_lines_before_import_section() -> None: """Test the case where the number of lines to output after imports has been explicitly set.""" test_input = """from a import b foo = 'bar' """ ln = "\n" # default case is no line added before the import assert isort.code(test_input) == (test_input) # test again with a custom number of lines before the import section assert isort.code(test_input, lines_before_imports=2) == 2 * ln + test_input comment = "# Comment\n" # test with a comment above assert isort.code(comment + ln + test_input, lines_before_imports=0) == comment + test_input # test with comments with empty lines assert ( isort.code(comment + ln + comment + 3 * ln + test_input, lines_before_imports=1) == comment + ln + comment + 1 * ln + test_input ) def test_custom_lines_after_import_section() -> None: """Test the case where the number of lines to output after imports has been explicitly set.""" test_input = "from a import b\nfoo = 'bar'\n" # default case is one space if not method or class after imports assert isort.code(test_input) == ("from a import b\n\nfoo = 'bar'\n") # test again with a custom number of lines after the import section assert isort.code(test_input, lines_after_imports=2) == ("from a import b\n\n\nfoo = 'bar'\n") def test_smart_lines_after_import_section() -> None: """Tests the default 'smart' behavior for dealing with lines after the import section""" # one space if not method or class after imports test_input = "from a import b\nfoo = 'bar'\n" assert isort.code(test_input) == ("from a import b\n\nfoo = 'bar'\n") # two spaces if a method or class after imports test_input = "from a import b\ndef my_function():\n pass\n" assert isort.code(test_input) == ("from a import b\n\n\ndef my_function():\n pass\n") # two spaces if an async method after imports test_input = "from a import b\nasync def my_function():\n pass\n" assert isort.code(test_input) == ("from a import b\n\n\nasync def my_function():\n pass\n") # two spaces if a method or class after imports - even if comment before function test_input = ( "from a import b\n" "# comment should be ignored\n" "def my_function():\n" " pass\n" ) assert isort.code(test_input) == ( "from a import b\n" "\n" "\n" "# comment should be ignored\n" "def my_function():\n" " pass\n" ) # the same logic does not apply to doc strings test_input = ( "from a import b\n" '"""\n' " comment should be ignored\n" '"""\n' "def my_function():\n" " pass\n" ) assert isort.code(test_input) == ( "from a import b\n" "\n" '"""\n' " comment should be ignored\n" '"""\n' "def my_function():\n" " pass\n" ) # Ensure logic doesn't incorrectly skip over assignments to multi-line strings test_input = 'from a import b\nX = """test\n"""\ndef my_function():\n pass\n' assert isort.code(test_input) == ( "from a import b\n" "\n" 'X = """test\n' '"""\n' "def my_function():\n" " pass\n" ) def test_settings_overwrite() -> None: """Test to ensure settings overwrite instead of trying to combine.""" assert Config(known_standard_library=["not_std_library"]).known_standard_library == frozenset( {"not_std_library"} ) assert Config(known_first_party=["thread"]).known_first_party == frozenset({"thread"}) def test_combined_from_and_as_imports() -> None: """Test to ensure it's possible to combine from and as imports.""" test_input = ( "from translate.misc.multistring import multistring\n" "from translate.storage import base, factory\n" "from translate.storage.placeables import general, parse as rich_parse\n" ) assert isort.code(test_input, combine_as_imports=True) == test_input assert isort.code(test_input, combine_as_imports=True, only_sections=True) == test_input test_input = "import os \nimport os as _os" test_output = "import os\nimport os as _os\n" assert isort.code(test_input) == test_output def test_as_imports_with_line_length() -> None: """Test to ensure it's possible to combine from and as imports.""" test_input = ( "from translate.storage import base as storage_base\n" "from translate.storage.placeables import general, parse as rich_parse\n" ) assert isort.code(code=test_input, combine_as_imports=False, line_length=40) == ( "from translate.storage import \\\n base as storage_base\n" "from translate.storage.placeables import \\\n general\n" "from translate.storage.placeables import \\\n parse as rich_parse\n" ) def test_keep_comments() -> None: """Test to ensure isort properly keeps comments in tact after sorting.""" # Straight Import test_input = "import foo # bar\n" assert isort.code(test_input) == test_input # Star import test_input_star = "from foo import * # bar\n" assert isort.code(test_input_star) == test_input_star # Force Single Line From Import test_input = "from foo import bar # comment\n" assert isort.code(test_input, force_single_line=True) == test_input # From import test_input = "from foo import bar # My Comment\n" assert isort.code(test_input) == test_input # More complicated case test_input = "from a import b # My Comment1\nfrom a import c # My Comment2\n" assert isort.code(test_input) == ( "from a import b # My Comment1\nfrom a import c # My Comment2\n" ) # Test case where imports comments make imports extend pass the line length test_input = ( "from a import b # My Comment1\n" "from a import c # My Comment2\n" "from a import d\n" ) assert isort.code(test_input, line_length=45) == ( "from a import b # My Comment1\n" "from a import c # My Comment2\n" "from a import d\n" ) # Test case where imports with comments will be beyond line length limit test_input = ( "from a import b, c # My Comment1\n" "from a import c, d # My Comment2 is really really really really long\n" ) assert isort.code(test_input, line_length=45) == ( "from a import ( # My Comment1; My Comment2 is really really really really long\n" " b, c, d)\n" ) # Test that comments are not stripped from 'import ... as ...' by default test_input = "from a import b as bb # b comment\nfrom a import c as cc # c comment\n" assert isort.code(test_input) == test_input # Test that 'import ... as ...' comments are not collected inappropriately test_input = ( "from a import b as bb # b comment\n" "from a import c as cc # c comment\n" "from a import d\n" ) assert isort.code(test_input) == test_input assert isort.code(test_input, combine_as_imports=True) == ( "from a import b as bb, c as cc, d # b comment; c comment\n" ) def test_multiline_split_on_dot() -> None: """Test to ensure isort correctly handles multiline imports, even when split right after a '.' """ test_input = ( "from my_lib.my_package.test.level_1.level_2.level_3.level_4.level_5.\\\n" " my_module import my_function" ) assert isort.code(test_input, line_length=70) == ( "from my_lib.my_package.test.level_1.level_2.level_3.level_4.level_5.my_module import \\\n" " my_function\n" ) def test_import_star() -> None: """Test to ensure isort handles star imports correctly""" test_input = "from blah import *\nfrom blah import _potato\n" assert isort.code(test_input) == ("from blah import *\nfrom blah import _potato\n") assert isort.code(test_input, combine_star=True) == ("from blah import *\n") def test_include_trailing_comma() -> None: """Test for the include_trailing_comma option""" test_output_grid = isort.code( code=SHORT_IMPORT, multi_line_output=WrapModes.GRID, line_length=40, include_trailing_comma=True, ) assert test_output_grid == ( "from third_party import (lib1, lib2,\n" " lib3, lib4,)\n" ) test_output_vertical = isort.code( code=SHORT_IMPORT, multi_line_output=WrapModes.VERTICAL, line_length=40, include_trailing_comma=True, ) assert test_output_vertical == ( "from third_party import (lib1,\n" " lib2,\n" " lib3,\n" " lib4,)\n" ) test_output_vertical_indent = isort.code( code=SHORT_IMPORT, multi_line_output=WrapModes.VERTICAL_HANGING_INDENT, line_length=40, include_trailing_comma=True, ) assert test_output_vertical_indent == ( "from third_party import (\n" " lib1,\n" " lib2,\n" " lib3,\n" " lib4,\n" ")\n" ) test_output_vertical_grid = isort.code( code=SHORT_IMPORT, multi_line_output=WrapModes.VERTICAL_GRID, line_length=40, include_trailing_comma=True, ) assert test_output_vertical_grid == ( "from third_party import (\n lib1, lib2, lib3, lib4,)\n" ) test_output_vertical_grid_grouped = isort.code( code=SHORT_IMPORT, multi_line_output=WrapModes.VERTICAL_GRID_GROUPED, line_length=40, include_trailing_comma=True, ) assert test_output_vertical_grid_grouped == ( "from third_party import (\n lib1, lib2, lib3, lib4,\n)\n" ) test_output_wrap_single_import_with_use_parentheses = isort.code( code=SINGLE_FROM_IMPORT, line_length=25, include_trailing_comma=True, use_parentheses=True ) assert test_output_wrap_single_import_with_use_parentheses == ( "from third_party import (\n lib1,)\n" ) test_output_wrap_single_import_vertical_indent = isort.code( code=SINGLE_FROM_IMPORT, line_length=25, multi_line_output=WrapModes.VERTICAL_HANGING_INDENT, include_trailing_comma=True, use_parentheses=True, ) assert test_output_wrap_single_import_vertical_indent == ( "from third_party import (\n lib1,\n)\n" ) trailing_comma_with_comment = ( "from six.moves.urllib.parse import urlencode " "# pylint: disable=no-name-in-module,import-error" ) expected_trailing_comma_with_comment = ( "from six.moves.urllib.parse import (\n" " urlencode, # pylint: disable=no-n" "ame-in-module,import-error\n)\n" ) trailing_comma_with_comment = isort.code( code=trailing_comma_with_comment, line_length=80, multi_line_output=WrapModes.VERTICAL_HANGING_INDENT, include_trailing_comma=True, use_parentheses=True, ) assert trailing_comma_with_comment == expected_trailing_comma_with_comment # The next time around, it should be equal trailing_comma_with_comment = isort.code( code=trailing_comma_with_comment, line_length=80, multi_line_output=WrapModes.VERTICAL_HANGING_INDENT, include_trailing_comma=True, use_parentheses=True, ) assert trailing_comma_with_comment == expected_trailing_comma_with_comment def test_similar_to_std_library() -> None: """Test to ensure modules that are named similarly to a standard library import don't end up clobbered """ test_input = "import datetime\n\nimport requests\nimport times\n" assert isort.code(test_input, known_third_party=["requests", "times"]) == test_input def test_correctly_placed_imports() -> None: """Test to ensure comments stay on correct placement after being sorted""" test_input = "from a import b # comment for b\nfrom a import c # comment for c\n" assert isort.code(test_input, force_single_line=True) == ( "from a import b # comment for b\nfrom a import c # comment for c\n" ) assert isort.code(test_input) == ( "from a import b # comment for b\nfrom a import c # comment for c\n" ) # Full example test from issue #143 test_input = ( "from itertools import chain\n" "\n" "from django.test import TestCase\n" "from model_mommy import mommy\n" "\n" "from apps.clientman.commands.download_usage_rights import " "associate_right_for_item_product\n" "from apps.clientman.commands.download_usage_rights import " "associate_right_for_item_product_d" "efinition\n" "from apps.clientman.commands.download_usage_rights import " "associate_right_for_item_product_d" "efinition_platform\n" "from apps.clientman.commands.download_usage_rights import " "associate_right_for_item_product_p" "latform\n" "from apps.clientman.commands.download_usage_rights import " "associate_right_for_territory_reta" "il_model\n" "from apps.clientman.commands.download_usage_rights import " "associate_right_for_territory_reta" "il_model_definition_platform_provider # noqa\n" "from apps.clientman.commands.download_usage_rights import " "clear_right_for_item_product\n" "from apps.clientman.commands.download_usage_rights import " "clear_right_for_item_product_defini" "tion\n" "from apps.clientman.commands.download_usage_rights import " "clear_right_for_item_product_defini" "tion_platform\n" "from apps.clientman.commands.download_usage_rights import " "clear_right_for_item_product_platfo" "rm\n" "from apps.clientman.commands.download_usage_rights import " "clear_right_for_territory_retail_mo" "del\n" "from apps.clientman.commands.download_usage_rights import " "clear_right_for_territory_retail_mo" "del_definition_platform_provider # noqa\n" "from apps.clientman.commands.download_usage_rights import " "create_download_usage_right\n" "from apps.clientman.commands.download_usage_rights import " "delete_download_usage_right\n" "from apps.clientman.commands.download_usage_rights import " "disable_download_for_item_product\n" "from apps.clientman.commands.download_usage_rights import " "disable_download_for_item_product_d" "efinition\n" "from apps.clientman.commands.download_usage_rights import " "disable_download_for_item_product_d" "efinition_platform\n" "from apps.clientman.commands.download_usage_rights import " "disable_download_for_item_product_p" "latform\n" "from apps.clientman.commands.download_usage_rights import " "disable_download_for_territory_reta" "il_model\n" "from apps.clientman.commands.download_usage_rights import " "disable_download_for_territory_reta" "il_model_definition_platform_provider # noqa\n" "from apps.clientman.commands.download_usage_rights import " "get_download_rights_for_item\n" "from apps.clientman.commands.download_usage_rights import " "get_right\n" ) assert ( isort.code( code=test_input, force_single_line=True, line_length=140, known_third_party=["django", "model_mommy"], default_section=sections.FIRSTPARTY, ) == test_input ) def test_auto_detection() -> None: """Initial test to ensure isort auto-detection works correctly - will grow over time as new issues are raised. """ # Issue 157 test_input = "import binascii\nimport os\n\nimport cv2\nimport requests\n" assert isort.code(test_input, known_third_party=["cv2", "requests"]) == test_input # alternative solution assert isort.code(test_input, default_section="THIRDPARTY") == test_input def test_same_line_statements() -> None: """Ensure isort correctly handles the case where a single line contains multiple statements including an import """ test_input = "import pdb; import nose\n" assert isort.code(test_input) == ("import pdb\n\nimport nose\n") test_input = "import pdb; pdb.set_trace()\nimport nose; nose.run()\n" assert isort.code(test_input) == test_input def test_long_line_comments() -> None: """Ensure isort correctly handles comments at the end of extremely long lines""" test_input = ( "from foo.utils.fabric_stuff.live import check_clean_live, deploy_live, " "sync_live_envdir, " "update_live_app, update_live_cron # noqa\n" "from foo.utils.fabric_stuff.stage import check_clean_stage, deploy_stage, " "sync_stage_envdir, " "update_stage_app, update_stage_cron # noqa\n" ) assert isort.code(code=test_input, line_length=100, balanced_wrapping=True) == ( "from foo.utils.fabric_stuff.live import (check_clean_live, deploy_live, # noqa\n" " sync_live_envdir, update_live_app, " "update_live_cron)\n" "from foo.utils.fabric_stuff.stage import (check_clean_stage, deploy_stage, # noqa\n" " sync_stage_envdir, update_stage_app, " "update_stage_cron)\n" ) def test_tab_character_in_import() -> None: """Ensure isort correctly handles import statements that contain a tab character""" test_input = ( "from __future__ import print_function\n" "from __future__ import\tprint_function\n" ) assert isort.code(test_input) == "from __future__ import print_function\n" def test_split_position() -> None: """Ensure isort splits on import instead of . when possible""" test_input = ( "from p24.shared.exceptions.master.host_state_flag_unchanged " "import HostStateUnchangedException\n" ) assert isort.code(test_input, line_length=80) == ( "from p24.shared.exceptions.master.host_state_flag_unchanged import \\\n" " HostStateUnchangedException\n" ) def test_place_comments() -> None: """Ensure manually placing imports works as expected""" test_input = ( "import sys\n" "import os\n" "import myproject.test\n" "import django.settings\n" "\n" "# isort: imports-thirdparty\n" "# isort: imports-firstparty\n" "# isort:imports-stdlib\n" "\n" ) expected_output = ( "\n# isort: imports-thirdparty\n" "import django.settings\n" "\n" "# isort: imports-firstparty\n" "import myproject.test\n" "\n" "# isort:imports-stdlib\n" "import os\n" "import sys\n" ) test_output = isort.code(test_input, known_first_party=["myproject"]) assert test_output == expected_output test_output = isort.code(test_output, known_first_party=["myproject"]) assert test_output == expected_output def test_placement_control() -> None: """Ensure that most specific placement control match wins""" test_input = ( "import os\n" "import sys\n" "from bottle import Bottle, redirect, response, run\n" "import p24.imports._argparse as argparse\n" "import p24.imports._subprocess as subprocess\n" "import p24.imports._VERSION as VERSION\n" "import p24.shared.media_wiki_syntax as syntax\n" ) test_output = isort.code( code=test_input, known_first_party=["p24", "p24.imports._VERSION"], known_standard_library=["p24.imports", "os", "sys"], known_third_party=["bottle"], default_section="THIRDPARTY", ) assert test_output == ( "import os\n" "import p24.imports._argparse as argparse\n" "import p24.imports._subprocess as subprocess\n" "import sys\n" "\n" "from bottle import Bottle, redirect, response, run\n" "\n" "import p24.imports._VERSION as VERSION\n" "import p24.shared.media_wiki_syntax as syntax\n" ) def test_custom_sections() -> None: """Ensure that most specific placement control match wins""" test_input = ( "import os\n" "import sys\n" "from django.conf import settings\n" "from bottle import Bottle, redirect, response, run\n" "import p24.imports._argparse as argparse\n" "from django.db import models\n" "import p24.imports._subprocess as subprocess\n" "import pandas as pd\n" "import p24.imports._VERSION as VERSION\n" "import numpy as np\n" "import p24.shared.media_wiki_syntax as syntax\n" ) test_output = isort.code( code=test_input, known_first_party=["p24", "p24.imports._VERSION"], import_heading_stdlib="Standard Library", import_heading_thirdparty="Third Party", import_heading_firstparty="First Party", import_heading_django="Django", import_heading_pandas="Pandas", known_standard_library=["p24.imports", "os", "sys"], known_third_party=["bottle"], known_django=["django"], known_pandas=["pandas", "numpy"], default_section="THIRDPARTY", sections=[ "FUTURE", "STDLIB", "DJANGO", "THIRDPARTY", "PANDAS", "FIRSTPARTY", "LOCALFOLDER", ], ) assert test_output == ( "# Standard Library\n" "import os\n" "import p24.imports._argparse as argparse\n" "import p24.imports._subprocess as subprocess\n" "import sys\n" "\n" "# Django\n" "from django.conf import settings\n" "from django.db import models\n" "\n" "# Third Party\n" "from bottle import Bottle, redirect, response, run\n" "\n" "# Pandas\n" "import numpy as np\n" "import pandas as pd\n" "\n" "# First Party\n" "import p24.imports._VERSION as VERSION\n" "import p24.shared.media_wiki_syntax as syntax\n" ) def test_custom_sections_exception_handling() -> None: """Ensure that appropriate exception is raised for missing sections""" test_input = "import requests\n" with pytest.raises(MissingSection): isort.code( code=test_input, default_section="THIRDPARTY", sections=[ "FUTURE", "STDLIB", "DJANGO", "PANDAS", "FIRSTPARTY", "LOCALFOLDER", ], ) test_input = "from requests import get, post\n" with pytest.raises(MissingSection): isort.code( code=test_input, default_section="THIRDPARTY", sections=[ "FUTURE", "STDLIB", "DJANGO", "PANDAS", "FIRSTPARTY", "LOCALFOLDER", ], ) def test_glob_known() -> None: """Ensure that most specific placement control match wins""" test_input = ( "import os\n" "from django_whatever import whatever\n" "import sys\n" "from django.conf import settings\n" "from . import another\n" ) test_output = isort.code( code=test_input, import_heading_stdlib="Standard Library", import_heading_thirdparty="Third Party", import_heading_firstparty="First Party", import_heading_django="Django", import_heading_djangoplugins="Django Plugins", import_heading_localfolder="Local", known_django=["django"], known_djangoplugins=["django_*"], default_section="THIRDPARTY", sections=[ "FUTURE", "STDLIB", "DJANGO", "DJANGOPLUGINS", "THIRDPARTY", "FIRSTPARTY", "LOCALFOLDER", ], ) assert test_output == ( "# Standard Library\n" "import os\n" "import sys\n" "\n" "# Django\n" "from django.conf import settings\n" "\n" "# Django Plugins\n" "from django_whatever import whatever\n" "\n" "# Local\n" "from . import another\n" ) def test_sticky_comments() -> None: """Test to ensure it is possible to make comments 'stick' above imports""" test_input = ( "import os\n" "\n" "# Used for type-hinting (ref: https://github.com/davidhalter/jedi/issues/414).\n" "from selenium.webdriver.remote.webdriver import WebDriver # noqa\n" ) assert isort.code(test_input) == test_input test_input = ( "from django import forms\n" "# While this couples the geographic forms to the GEOS library,\n" "# it decouples from database (by not importing SpatialBackend).\n" "from django.contrib.gis.geos import GEOSException, GEOSGeometry\n" "from django.utils.translation import ugettext_lazy as _\n" ) assert isort.code(test_input) == test_input def test_zipimport() -> None: """Imports ending in "import" shouldn't be clobbered""" test_input = "from zipimport import zipimport\n" assert isort.code(test_input) == test_input def test_from_ending() -> None: """Imports ending in "from" shouldn't be clobbered.""" test_input = "from foo import get_foo_from, get_foo\n" expected_output = "from foo import get_foo, get_foo_from\n" assert isort.code(test_input) == expected_output def test_from_first() -> None: """Tests the setting from_first works correctly""" test_input = "from os import path\nimport os\n" assert isort.code(test_input, from_first=True) == test_input def test_top_comments() -> None: """Ensure correct behavior with top comments""" test_input = ( "# -*- encoding: utf-8 -*-\n" "# Test comment\n" "#\n" "from __future__ import unicode_literals\n" ) assert isort.code(test_input) == test_input test_input = ( "# -*- coding: utf-8 -*-\n" "from django.db import models\n" "from django.utils.encoding import python_2_unicode_compatible\n" ) assert isort.code(test_input) == test_input test_input = "# Comment\nimport sys\n" assert isort.code(test_input) == test_input test_input = "# -*- coding\nimport sys\n" assert isort.code(test_input) == test_input def test_consistency() -> None: """Ensures consistency of handling even when dealing with non ordered-by-type imports""" test_input = "from sqlalchemy.dialects.postgresql import ARRAY, array\n" assert isort.code(test_input, order_by_type=True) == test_input def test_force_grid_wrap() -> None: """Ensures removing imports works as expected.""" test_input = "from bar import lib2\nfrom foo import lib6, lib7\n" test_output = isort.code( code=test_input, force_grid_wrap=2, multi_line_output=WrapModes.VERTICAL_HANGING_INDENT ) assert ( test_output == """from bar import lib2 from foo import ( lib6, lib7 ) """ ) test_output = isort.code( code=test_input, force_grid_wrap=3, multi_line_output=WrapModes.VERTICAL_HANGING_INDENT ) assert test_output == test_input def test_force_grid_wrap_long() -> None: """Ensure that force grid wrap still happens with long line length""" test_input = ( "from foo import lib6, lib7\n" "from bar import lib2\n" "from babar import something_that_is_kind_of_long" ) test_output = isort.code( code=test_input, force_grid_wrap=2, multi_line_output=WrapModes.VERTICAL_HANGING_INDENT, line_length=9999, ) assert ( test_output == """from babar import something_that_is_kind_of_long from bar import lib2 from foo import ( lib6, lib7 ) """ ) def test_uses_jinja_variables() -> None: """Test a basic set of imports that use jinja variables""" test_input = ( "import sys\n" "import os\n" "import myproject.{ test }\n" "import django.{ settings }" ) test_output = isort.code( code=test_input, known_third_party=["django"], known_first_party=["myproject"] ) assert test_output == ( "import os\n" "import sys\n" "\n" "import django.{ settings }\n" "\n" "import myproject.{ test }\n" ) test_input = "import {{ cookiecutter.repo_name }}\n" "from foo import {{ cookiecutter.bar }}\n" assert isort.code(test_input) == test_input def test_fcntl() -> None: """Test to ensure fcntl gets correctly recognized as stdlib import""" test_input = "import fcntl\nimport os\nimport sys\n" assert isort.code(test_input) == test_input def test_import_split_is_word_boundary_aware() -> None: """Test to ensure that isort splits words in a boundary aware manner""" test_input = ( "from mycompany.model.size_value_array_import_func import \\\n" " get_size_value_array_import_func_jobs" ) test_output = isort.code( code=test_input, multi_line_output=WrapModes.VERTICAL_HANGING_INDENT, line_length=79 ) assert test_output == ( "from mycompany.model.size_value_array_import_func import (\n" " get_size_value_array_import_func_jobs\n" ")\n" ) def test_other_file_encodings(tmpdir) -> None: """Test to ensure file encoding is respected""" for encoding in ("latin1", "utf8"): tmp_fname = tmpdir.join(f"test_{encoding}.py") file_contents = f"# coding: {encoding}\n\ns = u'ã'\n" tmp_fname.write_binary(file_contents.encode(encoding)) api.sort_file(Path(tmp_fname), file_path=Path(tmp_fname), settings_path=os.getcwd()) assert tmp_fname.read_text(encoding) == file_contents def test_other_file_encodings_in_place(tmpdir) -> None: """Test to ensure file encoding is respected when overwritten in place.""" for encoding in ("latin1", "utf8"): tmp_fname = tmpdir.join(f"test_{encoding}.py") file_contents = f"# coding: {encoding}\n\ns = u'ã'\n" tmp_fname.write_binary(file_contents.encode(encoding)) api.sort_file( Path(tmp_fname), file_path=Path(tmp_fname), settings_path=os.getcwd(), overwrite_in_place=True, ) assert tmp_fname.read_text(encoding) == file_contents def test_encoding_not_in_comment(tmpdir) -> None: """Test that 'encoding' not in a comment is ignored""" tmp_fname = tmpdir.join("test_encoding.py") file_contents = "class Foo\n coding: latin1\n\ns = u'ã'\n" tmp_fname.write_binary(file_contents.encode("utf8")) assert ( isort.code( Path(tmp_fname).read_text("utf8"), file_path=Path(tmp_fname), settings_path=os.getcwd() ) == file_contents ) def test_encoding_not_in_first_two_lines(tmpdir) -> None: """Test that 'encoding' not in the first two lines is ignored""" tmp_fname = tmpdir.join("test_encoding.py") file_contents = "\n\n# -*- coding: latin1\n\ns = u'ã'\n" tmp_fname.write_binary(file_contents.encode("utf8")) assert ( isort.code( Path(tmp_fname).read_text("utf8"), file_path=Path(tmp_fname), settings_path=os.getcwd() ) == file_contents ) def test_comment_at_top_of_file() -> None: """Test to ensure isort correctly handles top of file comments""" test_input = ( "# Comment one\n" "from django import forms\n" "# Comment two\n" "from django.contrib.gis.geos import GEOSException\n" ) assert isort.code(test_input) == test_input test_input = "# -*- coding: utf-8 -*-\nfrom django.db import models\n" assert isort.code(test_input) == test_input def test_alphabetic_sorting() -> None: """Test to ensure isort correctly handles single line imports""" test_input = ( "import unittest\n" "\n" "import ABC\n" "import Zope\n" "from django.contrib.gis.geos import GEOSException\n" "from plone.app.testing import getRoles\n" "from plone.app.testing import ManageRoles\n" "from plone.app.testing import setRoles\n" "from Products.CMFPlone import utils\n" ) options = { "force_single_line": True, "force_alphabetical_sort_within_sections": True, } # type: Dict[str, Any] output = isort.code(test_input, **options) assert output == test_input test_input = "# -*- coding: utf-8 -*-\nfrom django.db import models\n" assert isort.code(test_input) == test_input def test_alphabetic_sorting_multi_line() -> None: """Test to ensure isort correctly handles multiline import see: issue 364""" test_input = ( "from a import (CONSTANT_A, cONSTANT_B, CONSTANT_C, CONSTANT_D, CONSTANT_E,\n" " CONSTANT_F, CONSTANT_G, CONSTANT_H, CONSTANT_I, CONSTANT_J)\n" ) options = {"force_alphabetical_sort_within_sections": True} # type: Dict[str, Any] assert isort.code(test_input, **options) == test_input def test_comments_not_duplicated() -> None: """Test to ensure comments aren't duplicated: issue 303""" test_input = ( "from flask import url_for\n" "# Whole line comment\n" "from service import demo # inline comment\n" "from service import settings\n" ) output = isort.code(test_input) assert output.count("# Whole line comment\n") == 1 assert output.count("# inline comment\n") == 1 def test_top_of_line_comments() -> None: """Test to ensure top of line comments stay where they should: issue 260""" test_input = ( "# -*- coding: utf-8 -*-\n" "from django.db import models\n" "#import json as simplejson\n" "from myproject.models import Servidor\n" "\n" "import reversion\n" "\n" "import logging\n" ) output = isort.code(test_input) print(output) assert output.startswith("# -*- coding: utf-8 -*-\n") def test_basic_comment() -> None: """Test to ensure a basic comment wont crash isort""" test_input = "import logging\n# Foo\nimport os\n" assert isort.code(test_input) == test_input def test_shouldnt_add_lines() -> None: """Ensure that isort doesn't add a blank line when a top of import comment is present, See: issue #316 """ test_input = '"""Text"""\n' "# This is a comment\nimport pkg_resources\n" assert isort.code(test_input) == test_input def test_sections_parsed_correct(tmpdir) -> None: """Ensure that modules for custom sections parsed as list from config file and isort result is correct """ conf_file_data = ( "[settings]\n" "sections=FUTURE,STDLIB,THIRDPARTY,FIRSTPARTY,LOCALFOLDER,COMMON\n" "known_common=nose\n" "import_heading_common=Common Library\n" "import_heading_stdlib=Standard Library\n" ) test_input = "import os\nfrom nose import *\nimport nose\nfrom os import path" correct_output = ( "# Standard Library\n" "import os\n" "from os import path\n" "\n" "# Common Library\n" "import nose\n" "from nose import *\n" ) tmpdir.join(".isort.cfg").write(conf_file_data) assert isort.code(test_input, settings_path=str(tmpdir)) == correct_output def test_pyproject_conf_file(tmpdir) -> None: """Ensure that modules for custom sections parsed as list from config file and isort result is correct """ conf_file_data = ( "[build-system]\n" 'requires = ["setuptools", "wheel"]\n' "[project]\n" 'name = "isort"\n' 'version = "0.1.0"\n' 'license = "MIT"\n' "[tool.isort]\n" "lines_between_types=1\n" 'known_common="nose"\n' 'known_first_party="foo"\n' 'import_heading_common="Common Library"\n' 'import_heading_stdlib="Standard Library"\n' 'sections="FUTURE,STDLIB,THIRDPARTY,FIRSTPARTY,LOCALFOLDER,COMMON"\n' "include_trailing_comma = true\n" ) test_input = "import os\nfrom nose import *\nimport nose\nfrom os import path\nimport foo" correct_output = ( "# Standard Library\n" "import os\n" "\n" "from os import path\n" "\n" "import foo\n" "\n" "# Common Library\n" "import nose\n" "\n" "from nose import *\n" ) tmpdir.join("pyproject.toml").write(conf_file_data) assert isort.code(test_input, settings_path=str(tmpdir)) == correct_output def test_alphabetic_sorting_no_newlines() -> None: """Test to ensure that alphabetical sort does not erroneously introduce new lines (issue #328) """ test_input = "import os\n" test_output = isort.code(code=test_input, force_alphabetical_sort_within_sections=True) assert test_input == test_output test_input = "import os\n" "import unittest\n" "\n" "from a import b\n" "\n" "\n" "print(1)\n" test_output = isort.code( code=test_input, force_alphabetical_sort_within_sections=True, lines_after_imports=2 ) assert test_input == test_output def test_sort_within_section() -> None: """Test to ensure its possible to force isort to sort within sections""" test_input = ( "from Foob import ar\n" "import foo\n" "from foo import bar\n" "from foo.bar import Quux, baz\n" ) test_output = isort.code(test_input, force_sort_within_sections=True) assert test_output == test_input test_input = ( "import foo\n" "from foo import bar\n" "from foo.bar import baz\n" "from foo.bar import Quux\n" "from Foob import ar\n" ) test_output = isort.code( code=test_input, force_sort_within_sections=True, order_by_type=False, force_single_line=True, ) assert test_output == test_input test_input = ( "import foo\n" "from foo import bar\n" "from foo.bar import baz\n" "from foo.bar import Quux\n" "from Foob import ar\n" ) test_output = isort.code( code=test_input, case_sensitive=True, force_sort_within_sections=True, order_by_type=False, force_single_line=True, ) assert test_output == test_input test_input = ( "from Foob import ar\n" "import foo\n" "from foo import Quux\n" "from foo import baz\n" ) test_output = isort.code( code=test_input, case_sensitive=True, force_sort_within_sections=True, order_by_type=True, force_single_line=True, ) assert test_output == test_input def test_sort_within_section_case_honored() -> None: """Ensure isort can do partial case-sensitive sorting in force-sorted sections""" test_input = ( "import foo\n" "from foo import bar\n" "from foo.bar import Quux, baz\n" "from Foob import ar\n" ) test_output = isort.code( test_input, force_sort_within_sections=True, honor_case_in_force_sorted_sections=True ) assert test_output == test_input test_input = ( "import foo\n" "from foo import bar\n" "from foo.bar import baz\n" "from foo.bar import Quux\n" "from Foob import ar\n" ) test_output = isort.code( code=test_input, force_sort_within_sections=True, honor_case_in_force_sorted_sections=True, order_by_type=False, force_single_line=True, ) assert test_output == test_input test_input = ( "from Foob import ar\n" "import foo\n" "from foo import bar\n" "from foo.bar import baz\n" "from foo.bar import Quux\n" ) test_output = isort.code( code=test_input, case_sensitive=True, force_sort_within_sections=True, honor_case_in_force_sorted_sections=True, order_by_type=False, force_single_line=True, ) assert test_output == test_input test_input = ( "from Foob import ar\n" "import foo\n" "from foo import Quux\n" "from foo import baz\n" ) test_output = isort.code( code=test_input, case_sensitive=True, force_sort_within_sections=True, honor_case_in_force_sorted_sections=True, order_by_type=True, force_single_line=True, ) assert test_output == test_input def test_sorting_with_two_top_comments() -> None: """Test to ensure isort will sort files that contain 2 top comments""" test_input = "#! comment1\n''' comment2\n'''\nimport b\nimport a\n" assert isort.code(test_input) == ("#! comment1\n''' comment2\n'''\nimport a\nimport b\n") def test_lines_between_sections() -> None: """Test to ensure lines_between_sections works""" test_input = "from bar import baz\nimport os\n" assert isort.code(test_input, lines_between_sections=0) == ("import os\nfrom bar import baz\n") assert isort.code(test_input, lines_between_sections=2) == ( "import os\n\n\nfrom bar import baz\n" ) def test_forced_sepatate_globs() -> None: """Test to ensure that forced_separate glob matches lines""" test_input = ( "import os\n" "\n" "from myproject.foo.models import Foo\n" "\n" "from myproject.utils import util_method\n" "\n" "from myproject.bar.models import Bar\n" "\n" "import sys\n" ) test_output = isort.code(code=test_input, forced_separate=["*.models"], line_length=120) assert test_output == ( "import os\n" "import sys\n" "\n" "from myproject.utils import util_method\n" "\n" "from myproject.bar.models import Bar\n" "from myproject.foo.models import Foo\n" ) def test_no_additional_lines_issue_358() -> None: """Test to ensure issue 358 is resolved and running isort multiple times does not add extra newlines """ test_input = ( '"""This is a docstring"""\n' "# This is a comment\n" "from __future__ import (\n" " absolute_import,\n" " division,\n" " print_function,\n" " unicode_literals\n" ")\n" ) expected_output = ( '"""This is a docstring"""\n' "# This is a comment\n" "from __future__ import (\n" " absolute_import,\n" " division,\n" " print_function,\n" " unicode_literals\n" ")\n" ) test_output = isort.code( code=test_input, multi_line_output=WrapModes.VERTICAL_HANGING_INDENT, line_length=20 ) assert test_output == expected_output test_output = isort.code( code=test_output, multi_line_output=WrapModes.VERTICAL_HANGING_INDENT, line_length=20 ) assert test_output == expected_output for _attempt in range(5): test_output = isort.code( code=test_output, multi_line_output=WrapModes.VERTICAL_HANGING_INDENT, line_length=20 ) assert test_output == expected_output test_input = ( '"""This is a docstring"""\n' "\n" "# This is a comment\n" "from __future__ import (\n" " absolute_import,\n" " division,\n" " print_function,\n" " unicode_literals\n" ")\n" ) expected_output = ( '"""This is a docstring"""\n' "\n" "# This is a comment\n" "from __future__ import (\n" " absolute_import,\n" " division,\n" " print_function,\n" " unicode_literals\n" ")\n" ) test_output = isort.code( code=test_input, multi_line_output=WrapModes.VERTICAL_HANGING_INDENT, line_length=20 ) assert test_output == expected_output test_output = isort.code( code=test_output, multi_line_output=WrapModes.VERTICAL_HANGING_INDENT, line_length=20 ) assert test_output == expected_output for _attempt in range(5): test_output = isort.code( code=test_output, multi_line_output=WrapModes.VERTICAL_HANGING_INDENT, line_length=20 ) assert test_output == expected_output def test_import_by_paren_issue_375() -> None: """Test to ensure isort can correctly handle sorting imports where the paren is directly by the import body """ test_input = "from .models import(\n Foo,\n Bar,\n)\n" assert isort.code(test_input) == "from .models import Bar, Foo\n" def test_import_by_paren_issue_460() -> None: """Test to ensure isort can doesnt move comments around""" test_input = """ # First comment # Second comment # third comment import io import os """ assert isort.code(test_input) == test_input def test_function_with_docstring() -> None: """Test to ensure isort can correctly sort imports when the first found content is a function with a docstring """ add_imports = ["from __future__ import unicode_literals"] test_input = "def foo():\n" ' """ Single line triple quoted doctring """\n' " pass\n" expected_output = ( "from __future__ import unicode_literals\n" "\n" "\n" "def foo():\n" ' """ Single line triple quoted doctring """\n' " pass\n" ) assert isort.code(test_input, add_imports=add_imports) == expected_output def test_plone_style() -> None: """Test to ensure isort correctly plone style imports""" test_input = ( "from django.contrib.gis.geos import GEOSException\n" "from plone.app.testing import getRoles\n" "from plone.app.testing import ManageRoles\n" "from plone.app.testing import setRoles\n" "from Products.CMFPlone import utils\n" "\n" "import ABC\n" "import unittest\n" "import Zope\n" ) options = {"force_single_line": True, "force_alphabetical_sort": True} # type: Dict[str, Any] assert isort.code(test_input, **options) == test_input def test_third_party_case_sensitive() -> None: """Modules which match builtins by name but not on case should not be picked up on Windows.""" test_input = "import thirdparty\nimport os\nimport ABC\n" expected_output = "import os\n\nimport ABC\nimport thirdparty\n" assert isort.code(test_input) == expected_output def test_exists_case_sensitive_file(tmpdir) -> None: """Test exists_case_sensitive function for a file.""" exists_case_sensitive.cache_clear() tmpdir.join("module.py").ensure(file=1) assert exists_case_sensitive(str(tmpdir.join("module.py"))) assert not exists_case_sensitive(str(tmpdir.join("MODULE.py"))) def test_exists_case_sensitive_directory(tmpdir) -> None: """Test exists_case_sensitive function for a directory.""" exists_case_sensitive.cache_clear() tmpdir.join("pkg").ensure(dir=1) assert exists_case_sensitive(str(tmpdir.join("pkg"))) assert not exists_case_sensitive(str(tmpdir.join("PKG"))) def test_sys_path_mutation(tmpdir) -> None: """Test to ensure sys.path is not modified""" tmpdir.mkdir("src").mkdir("a") test_input = "from myproject import test" options = {"virtual_env": str(tmpdir)} # type: Dict[str, Any] expected_length = len(sys.path) isort.code(test_input, **options) assert len(sys.path) == expected_length isort.code(test_input, old_finders=True, **options) def test_long_single_line() -> None: """Test to ensure long single lines get handled correctly""" output = isort.code( code="from ..views import (" " _a," "_xxxxxx_xxxxxxx_xxxxxxxx_xxx_xxxxxxx as xxxxxx_xxxxxxx_xxxxxxxx_xxx_xxxxxxx)", line_length=79, ) for line in output.split("\n"): assert len(line) <= 79 output = isort.code( code="from ..views import (" " _a," "_xxxxxx_xxxxxxx_xxxxxxxx_xxx_xxxxxxx as xxxxxx_xxxxxxx_xxxxxxxx_xxx_xxxxxxx)", line_length=79, combine_as_imports=True, ) for line in output.split("\n"): assert len(line) <= 79 def test_import_inside_class_issue_432() -> None: """Test to ensure issue 432 is resolved and isort doesn't insert imports in the middle of classes """ test_input = "# coding=utf-8\nclass Foo:\n def bar(self):\n pass\n" expected_output = ( "# coding=utf-8\n" "import baz\n" "\n" "\n" "class Foo:\n" " def bar(self):\n" " pass\n" ) assert isort.code(test_input, add_imports=["import baz"]) == expected_output def test_wildcard_import_without_space_issue_496() -> None: """Test to ensure issue #496: wildcard without space, is resolved""" test_input = "from findorserver.coupon.models import*" expected_output = "from findorserver.coupon.models import *\n" assert isort.code(test_input) == expected_output def test_import_line_mangles_issues_491() -> None: """Test to ensure comment on import with parens doesn't cause issues""" test_input = "import os # ([\n\n" 'print("hi")\n' assert isort.code(test_input) == test_input def test_import_line_mangles_issues_505() -> None: """Test to ensure comment on import with parens doesn't cause issues""" test_input = "from sys import * # (\n\n\ndef test():\n" ' print("Test print")\n' assert isort.code(test_input) == test_input def test_import_line_mangles_issues_439() -> None: """Test to ensure comment on import with parens doesn't cause issues""" test_input = "import a # () import\nfrom b import b\n" assert isort.code(test_input) == test_input def test_alias_using_paren_issue_466() -> None: """Test to ensure issue #466: Alias causes slash incorrectly is resolved""" test_input = ( "from django.db.backends.mysql.base import DatabaseWrapper as MySQLDatabaseWrapper\n" ) expected_output = ( "from django.db.backends.mysql.base import (\n" " DatabaseWrapper as MySQLDatabaseWrapper)\n" ) assert isort.code(test_input, line_length=50, use_parentheses=True) == expected_output test_input = ( "from django.db.backends.mysql.base import DatabaseWrapper as MySQLDatabaseWrapper\n" ) expected_output = ( "from django.db.backends.mysql.base import (\n" " DatabaseWrapper as MySQLDatabaseWrapper\n" ")\n" ) assert ( isort.code( code=test_input, line_length=50, multi_line_output=WrapModes.VERTICAL_GRID_GROUPED, use_parentheses=True, ) == expected_output ) def test_long_alias_using_paren_issue_957() -> None: test_input = ( "from package import module as very_very_very_very_very_very_very" "_very_very_very_long_alias\n" ) expected_output = ( "from package import (\n" " module as very_very_very_very_very_very_very_very_very_very_long_alias\n" ")\n" ) out = isort.code( code=test_input, line_length=50, use_parentheses=True, multi_line_output=WrapModes.VERTICAL_GRID_GROUPED, ) assert out == expected_output test_input = ( "from deep.deep.deep.deep.deep.deep.deep.deep.deep.package import module as " "very_very_very_very_very_very_very_very_very_very_long_alias\n" ) expected_output = ( "from deep.deep.deep.deep.deep.deep.deep.deep.deep.package import (\n" " module as very_very_very_very_very_very_very_very_very_very_long_alias\n" ")\n" ) out = isort.code( code=test_input, line_length=50, use_parentheses=True, multi_line_output=WrapModes.VERTICAL_GRID_GROUPED, ) assert out == expected_output test_input = ( "from deep.deep.deep.deep.deep.deep.deep.deep.deep.package " "import very_very_very_very_very_very_very_very_very_very_long_module as very_very_very_" "very_very_very_very_very_very_very_long_alias\n" ) expected_output = ( "from deep.deep.deep.deep.deep.deep.deep.deep.deep.package import (\n" " very_very_very_very_very_very_very_very_very_very_long_module as very_very_very_very" "_very_very_very_very_very_very_long_alias\n" ")\n" ) out = isort.code( code=test_input, line_length=50, use_parentheses=True, multi_line_output=WrapModes.VERTICAL_GRID_GROUPED, ) assert out == expected_output def test_strict_whitespace_by_default(capsys) -> None: test_input = "import os\nfrom django.conf import settings\n" assert not api.check_code_string(test_input) _, err = capsys.readouterr() assert "ERROR" in err assert err.endswith("Imports are incorrectly sorted and/or formatted.\n") def test_strict_whitespace_no_closing_newline_issue_676(capsys) -> None: test_input = "import os\n\nfrom django.conf import settings\n\nprint(1)" assert api.check_code_string(test_input) out, _ = capsys.readouterr() assert out == "" def test_ignore_whitespace(capsys) -> None: test_input = "import os\nfrom django.conf import settings\n" assert api.check_code_string(test_input, ignore_whitespace=True) out, _ = capsys.readouterr() assert out == "" def test_import_wraps_with_comment_issue_471() -> None: """Test to ensure issue #471 is resolved""" test_input = ( "from very_long_module_name import SuperLongClassName #@UnusedImport" " -- long string of comments which wrap over" ) expected_output = ( "from very_long_module_name import (\n" " SuperLongClassName) # @UnusedImport -- long string of comments which wrap over\n" ) assert ( isort.code(code=test_input, line_length=50, multi_line_output=1, use_parentheses=True) == expected_output ) def test_import_case_produces_inconsistent_results_issue_472() -> None: """Test to ensure sorting imports with same name but different case produces the same result across platforms """ test_input = ( "from sqlalchemy.dialects.postgresql import ARRAY\n" "from sqlalchemy.dialects.postgresql import array\n" ) assert isort.code(test_input, force_single_line=True) == test_input test_input = ( "from scrapy.core.downloader.handlers.http import " "HttpDownloadHandler, HTTPDownloadHandler\n" ) assert isort.code(test_input, line_length=100) == test_input def test_inconsistent_behavior_in_python_2_and_3_issue_479() -> None: """Test to ensure Python 2 and 3 have the same behavior""" test_input = ( "from workalendar.europe import UnitedKingdom\n" "\n" "from future.standard_library import hooks\n" ) assert isort.code(test_input, known_first_party=["future"]) == test_input def test_sort_within_section_comments_issue_436() -> None: """Test to ensure sort within sections leaves comments untouched""" test_input = ( "import os.path\n" "import re\n" "\n" "# report.py exists in ... comment line 1\n" "# this file needs to ... comment line 2\n" "# it must not be ... comment line 3\n" "import report\n" ) assert isort.code(test_input, force_sort_within_sections=True) == test_input def test_sort_within_sections_with_force_to_top_issue_473() -> None: """Test to ensure it's possible to sort within sections with items forced to top""" test_input = "import z\nimport foo\nfrom foo import bar\n" assert ( isort.code(code=test_input, force_sort_within_sections=True, force_to_top=["z"]) == test_input ) def test_force_sort_within_sections_with_relative_imports() -> None: """Test sorting of relative imports with force_sort_within_sections=True""" assert isort.check_code( """import . from . import foo from .. import a from ..alpha.beta import b from ..omega import c import .apple as bar from .mango import baz """, show_diff=True, force_sort_within_sections=True, ) def test_force_sort_within_sections_with_reverse_relative_imports() -> None: """Test reverse sorting of relative imports with force_sort_within_sections=True""" assert isort.check_code( """import . from . import foo from .mango import baz from ..alpha.beta import b from .. import a from ..omega import c import .apple as bar """, show_diff=True, force_sort_within_sections=True, reverse_relative=True, ) def test_sort_relative_in_force_sorted_sections_issue_1659() -> None: """Ensure relative imports are sorted within sections""" assert isort.check_code( """from .. import a from ..alpha.beta import b from ..omega import c import . from . import foo import .apple as bar from .mango import baz """, show_diff=True, force_sort_within_sections=True, sort_relative_in_force_sorted_sections=True, ) def test_reverse_sort_relative_in_force_sorted_sections_issue_1659() -> None: """Ensure reverse ordered relative imports are sorted within sections""" assert isort.check_code( """import . from . import foo import .apple as bar from .mango import baz from .. import a from ..alpha.beta import b from ..omega import c """, show_diff=True, force_sort_within_sections=True, sort_relative_in_force_sorted_sections=True, reverse_relative=True, ) def test_correct_number_of_new_lines_with_comment_issue_435() -> None: """Test to ensure that injecting a comment in-between imports doesn't mess up the new line spacing """ test_input = "import foo\n\n# comment\n\n\ndef baz():\n pass\n" assert isort.code(test_input) == test_input def test_future_below_encoding_issue_545() -> None: """Test to ensure future is always below comment""" test_input = ( "#!/usr/bin/env python\n" "from __future__ import print_function\n" "import logging\n" "\n" 'print("hello")\n' ) expected_output = ( "#!/usr/bin/env python\n" "from __future__ import print_function\n" "\n" "import logging\n" "\n" 'print("hello")\n' ) assert isort.code(test_input) == expected_output def test_no_extra_lines_issue_557() -> None: """Test to ensure no extra lines are prepended""" test_input = ( "import os\n" "\n" "from scrapy.core.downloader.handlers.http import " "HttpDownloadHandler, HTTPDownloadHandler\n" ) expected_output = ( "import os\n" "from scrapy.core.downloader.handlers.http import HttpDownloadHandler, " "HTTPDownloadHandler\n" ) assert ( isort.code( code=test_input, force_alphabetical_sort=True, force_sort_within_sections=True, line_length=100, ) == expected_output ) def test_long_import_wrap_support_with_mode_2() -> None: """Test to ensure mode 2 still allows wrapped imports with slash""" test_input = ( "from foobar.foobar.foobar.foobar import \\\n" " an_even_longer_function_name_over_80_characters\n" ) assert ( isort.code(code=test_input, multi_line_output=WrapModes.HANGING_INDENT, line_length=80) == test_input ) def test_pylint_comments_incorrectly_wrapped_issue_571() -> None: """Test to ensure pylint comments don't get wrapped""" test_input = ( "from PyQt5.QtCore import QRegExp # @UnresolvedImport pylint: disable=import-error," "useless-suppression\n" ) expected_output = ( "from PyQt5.QtCore import \\\n" " QRegExp # @UnresolvedImport pylint: disable=import-error,useless-suppression\n" ) assert isort.code(test_input, line_length=60) == expected_output def test_ensure_async_methods_work_issue_537() -> None: """Test to ensure async methods are correctly identified""" test_input = ( "from myapp import myfunction\n" "\n" "\n" "async def test_myfunction(test_client, app):\n" " a = await myfunction(test_client, app)\n" ) assert isort.code(test_input) == test_input def test_ensure_as_imports_sort_correctly_within_from_imports_issue_590() -> None: """Test to ensure combination from and as import statements are sorted correct""" test_input = "from os import defpath\nfrom os import pathsep as separator\n" assert isort.code(test_input, force_sort_within_sections=True) == test_input test_input = "from os import defpath\nfrom os import pathsep as separator\n" assert isort.code(test_input) == test_input test_input = "from os import defpath\nfrom os import pathsep as separator\n" assert isort.code(test_input, force_single_line=True) == test_input def test_ensure_line_endings_are_preserved_issue_493() -> None: """Test to ensure line endings are not converted""" test_input = "from os import defpath\r\nfrom os import pathsep as separator\r\n" assert isort.code(test_input) == test_input test_input = "from os import defpath\rfrom os import pathsep as separator\r" assert isort.code(test_input) == test_input test_input = "from os import defpath\nfrom os import pathsep as separator\n" assert isort.code(test_input) == test_input def test_not_splitted_sections() -> None: whiteline = "\n" stdlib_section = "import unittest\n" firstparty_section = "from app.pkg1 import mdl1\n" local_section = "from .pkg2 import mdl2\n" statement = "foo = bar\n" test_input = ( stdlib_section + whiteline + firstparty_section + whiteline + local_section + whiteline + statement ) assert isort.code(test_input, known_first_party=["app"]) == test_input assert isort.code(test_input, no_lines_before=["LOCALFOLDER"], known_first_party=["app"]) == ( stdlib_section + whiteline + firstparty_section + local_section + whiteline + statement ) # by default STDLIB and FIRSTPARTY sections are split by THIRDPARTY section, # so don't merge them if THIRDPARTY imports aren't exist assert ( isort.code(test_input, no_lines_before=["FIRSTPARTY"], known_first_party=["app"]) == test_input ) # in case when THIRDPARTY section is excluded from sections list, # it's ok to merge STDLIB and FIRSTPARTY assert isort.code( code=test_input, sections=["STDLIB", "FIRSTPARTY", "LOCALFOLDER"], no_lines_before=["FIRSTPARTY"], known_first_party=["app"], ) == (stdlib_section + firstparty_section + whiteline + local_section + whiteline + statement) # it doesn't change output, because stdlib packages don't have any whitelines before them assert ( isort.code(test_input, no_lines_before=["STDLIB"], known_first_party=["app"]) == test_input ) def test_no_lines_before_empty_section() -> None: test_input = "import first\nimport custom\n" assert ( isort.code( code=test_input, known_third_party=["first"], known_custom=["custom"], sections=["THIRDPARTY", "LOCALFOLDER", "CUSTOM"], no_lines_before=["THIRDPARTY", "LOCALFOLDER", "CUSTOM"], ) == test_input ) def test_no_inline_sort() -> None: """Test to ensure multiple `from` imports in one line are not sorted if `--no-inline-sort` flag is enabled. If `--force-single-line-imports` flag is enabled, then `--no-inline-sort` is ignored. """ test_input = "from foo import a, c, b\n" assert isort.code(test_input, no_inline_sort=True, force_single_line=False) == test_input assert ( isort.code(test_input, no_inline_sort=False, force_single_line=False) == "from foo import a, b, c\n" ) expected = "from foo import a\nfrom foo import b\nfrom foo import c\n" assert isort.code(test_input, no_inline_sort=False, force_single_line=True) == expected assert isort.code(test_input, no_inline_sort=True, force_single_line=True) == expected def test_relative_import_of_a_module() -> None: """Imports can be dynamically created (PEP302) and is used by modules such as six. This test ensures that these types of imports are still sorted to the correct type instead of being categorized as local. """ test_input = ( "from __future__ import absolute_import\n" "\n" "import itertools\n" "\n" "from six import add_metaclass\n" "\n" "from six.moves import asd\n" ) expected_results = ( "from __future__ import absolute_import\n" "\n" "import itertools\n" "\n" "from six import add_metaclass\n" "from six.moves import asd\n" ) sorted_result = isort.code(test_input, force_single_line=True) assert sorted_result == expected_results def test_escaped_parens_sort() -> None: test_input = "from foo import \\ \n(a,\nb,\nc)\n" expected = "from foo import a, b, c\n" assert isort.code(test_input) == expected def test_escaped_parens_sort_with_comment() -> None: test_input = "from foo import \\ \n(a,\nb,# comment\nc)\n" expected = "from foo import b # comment\nfrom foo import a, c\n" assert isort.code(test_input) == expected def test_escaped_parens_sort_with_first_comment() -> None: test_input = "from foo import \\ \n(a,# comment\nb,\nc)\n" expected = "from foo import a # comment\nfrom foo import b, c\n" assert isort.code(test_input) == expected def test_escaped_no_parens_sort_with_first_comment() -> None: test_input = "from foo import a, \\\nb, \\\nc # comment\n" expected = "from foo import c # comment\nfrom foo import a, b\n" assert isort.code(test_input) == expected @pytest.mark.skip(reason="TODO: Duplicates currently not handled.") def test_to_ensure_imports_are_brought_to_top_issue_651() -> None: test_input = ( "from __future__ import absolute_import, unicode_literals\n" "\n" 'VAR = """\n' "multiline text\n" '"""\n' "\n" "from __future__ import unicode_literals\n" "from __future__ import absolute_import\n" ) expected_output = ( "from __future__ import absolute_import, unicode_literals\n" "\n" 'VAR = """\n' "multiline text\n" '"""\n' ) assert isort.code(test_input) == expected_output def test_to_ensure_importing_from_imports_module_works_issue_662() -> None: test_input = ( "@wraps(fun)\n" "def __inner(*args, **kwargs):\n" " from .imports import qualname\n" "\n" " warn(description=description or qualname(fun), deprecation=deprecation, " "removal=removal)\n" ) assert isort.code(test_input) == test_input def test_to_ensure_no_unexpected_changes_issue_666() -> None: test_input = ( "from django.conf import settings\n" "from django.core.management import call_command\n" "from django.core.management.base import BaseCommand\n" "from django.utils.translation import ugettext_lazy as _\n" "\n" 'TEMPLATE = """\n' "# This file is generated automatically with the management command\n" "#\n" "# manage.py bis_compile_i18n\n" "#\n" "# please dont change it manually.\n" "from django.utils.translation import ugettext_lazy as _\n" '"""\n' ) assert isort.code(test_input) == test_input def test_to_ensure_tabs_dont_become_space_issue_665() -> None: test_input = "import os\n\n\ndef my_method():\n\tpass\n" assert isort.code(test_input) == test_input def test_new_lines_are_preserved() -> None: with NamedTemporaryFile("w", suffix="py", delete=False) as rn_newline: pass try: with open(rn_newline.name, mode="w", newline="") as rn_newline_input: rn_newline_input.write("import sys\r\nimport os\r\n") api.sort_file(rn_newline.name, settings_path=os.getcwd()) with open(rn_newline.name) as new_line_file: print(new_line_file.read()) with open(rn_newline.name, newline="") as rn_newline_file: rn_newline_contents = rn_newline_file.read() assert rn_newline_contents == "import os\r\nimport sys\r\n" finally: os.remove(rn_newline.name) with NamedTemporaryFile("w", suffix="py", delete=False) as r_newline: pass try: with open(r_newline.name, mode="w", newline="") as r_newline_input: r_newline_input.write("import sys\rimport os\r") api.sort_file(r_newline.name, settings_path=os.getcwd()) with open(r_newline.name, newline="") as r_newline_file: r_newline_contents = r_newline_file.read() assert r_newline_contents == "import os\rimport sys\r" finally: os.remove(r_newline.name) with NamedTemporaryFile("w", suffix="py", delete=False) as n_newline: pass try: with open(n_newline.name, mode="w", newline="") as n_newline_input: n_newline_input.write("import sys\nimport os\n") api.sort_file(n_newline.name, settings_path=os.getcwd()) with open(n_newline.name, newline="") as n_newline_file: n_newline_contents = n_newline_file.read() assert n_newline_contents == "import os\nimport sys\n" finally: os.remove(n_newline.name) def test_forced_separate_is_deterministic_issue_774(tmpdir) -> None: config_file = tmpdir.join("setup.cfg") config_file.write( "[isort]\n" "forced_separate:\n" " separate1\n" " separate2\n" " separate3\n" " separate4\n" ) test_input = ( "import time\n" "\n" "from separate1 import foo\n" "\n" "from separate2 import bar\n" "\n" "from separate3 import baz\n" "\n" "from separate4 import quux\n" ) assert isort.code(test_input, settings_file=config_file.strpath) == test_input def test_monkey_patched_urllib() -> None: with pytest.raises(ImportError): # Previous versions of isort monkey patched urllib which caused unusual # importing for other projects. from urllib import quote # type: ignore # noqa: F401 def test_argument_parsing() -> None: from isort.main import parse_args args = parse_args(["--dt", "-t", "foo", "--skip=bar", "baz.py", "--os"]) assert args["order_by_type"] is False assert args["force_to_top"] == ["foo"] assert args["skip"] == ["bar"] assert args["files"] == ["baz.py"] assert args["only_sections"] is True @pytest.mark.parametrize("multiprocess", [False, True]) def test_command_line(tmpdir, capfd, multiprocess: bool) -> None: from isort.main import main tmpdir.join("file1.py").write("import re\nimport os\n\nimport contextlib\n\n\nimport isort") tmpdir.join("file2.py").write( "import collections\nimport time\n\nimport abc" "\n\n\nimport isort" ) arguments = [str(tmpdir), "--settings-path", os.getcwd()] if multiprocess: arguments.extend(["--jobs", "2"]) main(arguments) assert ( tmpdir.join("file1.py").read() == "import contextlib\nimport os\nimport re\n\nimport isort\n" ) assert ( tmpdir.join("file2.py").read() == "import abc\nimport collections\nimport time\n\nimport isort\n" ) if not (sys.platform.startswith("win") or sys.platform.startswith("darwin")): out, err = capfd.readouterr() assert not [error for error in err.split("\n") if error and "warning:" not in error] # it informs us about fixing the files: assert str(tmpdir.join("file1.py")) in out assert str(tmpdir.join("file2.py")) in out @pytest.mark.parametrize("quiet", [False, True]) def test_quiet(tmpdir, capfd, quiet: bool) -> None: if sys.platform.startswith("win"): return from isort.main import main tmpdir.join("file1.py").write("import re\nimport os") tmpdir.join("file2.py").write("") arguments = [str(tmpdir)] if quiet: arguments.append("-q") main(arguments) out, err = capfd.readouterr() assert not err assert bool(out) != quiet @pytest.mark.parametrize("enabled", [False, True]) def test_safety_skips(tmpdir, enabled: bool) -> None: tmpdir.join("victim.py").write("# ...") toxdir = tmpdir.mkdir(".tox") toxdir.join("verysafe.py").write("# ...") tmpdir.mkdir("_build").mkdir("python3.7").join("importantsystemlibrary.py").write("# ...") tmpdir.mkdir(".pants.d").join("pants.py").write("import os") if enabled: config = Config(directory=str(tmpdir)) else: config = Config(skip=[], directory=str(tmpdir)) skipped: List[str] = [] broken: List[str] = [] codes = [str(tmpdir)] files.find(codes, config, skipped, broken) # if enabled files within nested unsafe directories should be skipped file_names = { os.path.relpath(f, str(tmpdir)) for f in files.find([str(tmpdir)], config, skipped, broken) } if enabled: assert file_names == {"victim.py"} assert len(skipped) == 3 else: assert file_names == { os.sep.join((".tox", "verysafe.py")), os.sep.join(("_build", "python3.7", "importantsystemlibrary.py")), os.sep.join((".pants.d", "pants.py")), "victim.py", } assert not skipped # directly pointing to files within unsafe directories shouldn't skip them either way file_names = { os.path.relpath(f, str(toxdir)) for f in files.find([str(toxdir)], Config(directory=str(toxdir)), skipped, broken) } assert file_names == {"verysafe.py"} @pytest.mark.parametrize( "skip_glob_assert", [ ([], 0, {os.sep.join(("code", "file.py"))}), (["**/*.py"], 1, set()), (["*/code/*.py"], 1, set()), ], ) def test_skip_glob(tmpdir, skip_glob_assert: Tuple[List[str], int, Set[str]]) -> None: skip_glob, skipped_count, file_names_expected = skip_glob_assert base_dir = tmpdir.mkdir("build") code_dir = base_dir.mkdir("code") code_dir.join("file.py").write("import os") config = Config(skip_glob=skip_glob, directory=str(base_dir)) skipped: List[str] = [] broken: List[str] = [] file_names = { os.path.relpath(f, str(base_dir)) for f in files.find([str(base_dir)], config, skipped, broken) } assert len(skipped) == skipped_count assert file_names == file_names_expected def test_broken(tmpdir) -> None: base_dir = tmpdir.mkdir("broken") config = Config(directory=str(base_dir)) skipped: List[str] = [] broken: List[str] = [] file_names = { os.path.relpath(f, str(base_dir)) for f in files.find(["not-exist"], config, skipped, broken) } assert len(broken) == 1 assert file_names == set() def test_comments_not_removed_issue_576() -> None: test_input = ( "import distutils\n" "# this comment is important and should not be removed\n" "from sys import api_version as api_version\n" ) assert isort.code(test_input) == test_input def test_reverse_relative_imports_issue_417() -> None: test_input = ( "from . import ipsum\n" "from . import lorem\n" "from .dolor import consecteur\n" "from .sit import apidiscing\n" "from .. import donec\n" "from .. import euismod\n" "from ..mi import iaculis\n" "from ..nec import tempor\n" "from ... import diam\n" "from ... import dui\n" "from ...eu import dignissim\n" "from ...ex import metus\n" ) assert isort.code(test_input, force_single_line=True, reverse_relative=True) == test_input def test_inconsistent_relative_imports_issue_577() -> None: test_input = ( "from ... import diam\n" "from ... import dui\n" "from ...eu import dignissim\n" "from ...ex import metus\n" "from .. import donec\n" "from .. import euismod\n" "from ..mi import iaculis\n" "from ..nec import tempor\n" "from . import ipsum\n" "from . import lorem\n" "from .dolor import consecteur\n" "from .sit import apidiscing\n" ) assert isort.code(test_input, force_single_line=True) == test_input def test_unwrap_issue_762() -> None: test_input = "from os.path \\\nimport (join, split)\n" assert isort.code(test_input) == "from os.path import join, split\n" test_input = "from os.\\\n path import (join, split)" assert isort.code(test_input) == "from os.path import join, split\n" def test_multiple_as_imports() -> None: test_input = "from a import b as b\nfrom a import b as bb\nfrom a import b as bb_\n" test_output = isort.code(test_input) assert test_output == test_input test_output = isort.code(test_input, combine_as_imports=True) assert test_output == "from a import b as b, b as bb, b as bb_\n" test_output = isort.code(test_input) assert test_output == test_input test_output = isort.code(code=test_input, combine_as_imports=True) assert test_output == "from a import b as b, b as bb, b as bb_\n" test_input = ( "from a import b\n" "from a import b as b\n" "from a import b as bb\n" "from a import b as bb_\n" ) test_output = isort.code(test_input) assert test_output == test_input test_output = isort.code(code=test_input, combine_as_imports=True) assert test_output == "from a import b, b as b, b as bb, b as bb_\n" test_input = ( "from a import b as e\n" "from a import b as c\n" "from a import b\n" "from a import b as f\n" ) test_output = isort.code(test_input) assert ( test_output == "from a import b\nfrom a import b as c\nfrom a import b as e\nfrom a import b as f\n" ) test_output = isort.code(code=test_input, no_inline_sort=True) assert ( test_output == "from a import b\nfrom a import b as c\nfrom a import b as e\nfrom a import b as f\n" ) test_output = isort.code(code=test_input, combine_as_imports=True) assert test_output == "from a import b, b as c, b as e, b as f\n" test_output = isort.code(code=test_input, combine_as_imports=True, no_inline_sort=True) assert test_output == "from a import b, b as e, b as c, b as f\n" test_input = "import a as a\nimport a as aa\nimport a as aa_\n" test_output = isort.code(code=test_input, combine_as_imports=True) assert test_output == test_input assert test_output == "import a as a\nimport a as aa\nimport a as aa_\n" test_output = isort.code(code=test_input, combine_as_imports=True) assert test_output == test_input def test_all_imports_from_single_module() -> None: test_input = ( "import a\n" "from a import *\n" "from a import b as d\n" "from a import z, x, y\n" "from a import b\n" "from a import w, i as j\n" "from a import b as c, g as h\n" "from a import e as f\n" ) test_output = isort.code( code=test_input, combine_star=False, combine_as_imports=False, force_single_line=False, no_inline_sort=False, ) assert test_output == ( "import a\n" "from a import *\n" "from a import b\n" "from a import b as c\n" "from a import b as d\n" "from a import e as f\n" "from a import g as h\n" "from a import i as j\n" "from a import w, x, y, z\n" ) test_input = ( "import a\n" "from a import *\n" "from a import z, x, y\n" "from a import b\n" "from a import w\n" ) test_output = isort.code( code=test_input, combine_star=True, combine_as_imports=False, force_single_line=False, no_inline_sort=False, ) assert test_output == "import a\nfrom a import *\n" test_input += """ from a import b as c from a import b as d from a import e as f from a import g as h from a import i as j """ test_output = isort.code( code=test_input, combine_star=False, combine_as_imports=True, force_single_line=False, no_inline_sort=False, ) assert test_output == ( "import a\n" "from a import *\n" "from a import b, b as c, b as d, e as f, g as h, i as j, w, x, y, z\n" ) test_output = isort.code( code=test_input, combine_star=False, combine_as_imports=False, force_single_line=True, no_inline_sort=False, ) assert test_output == ( "import a\n" "from a import *\n" "from a import b\n" "from a import b as c\n" "from a import b as d\n" "from a import e as f\n" "from a import g as h\n" "from a import i as j\n" "from a import w\n" "from a import x\n" "from a import y\n" "from a import z\n" ) test_input = ( "import a\n" "from a import *\n" "from a import b\n" "from a import b as d\n" "from a import b as c\n" "from a import z, x, y, w\n" "from a import i as j\n" "from a import g as h\n" "from a import e as f\n" ) test_output = isort.code( code=test_input, combine_star=False, combine_as_imports=False, force_single_line=False, no_inline_sort=True, ) assert test_output == ( "import a\n" "from a import *\n" "from a import b\n" "from a import b as c\n" "from a import b as d\n" "from a import z, x, y, w\n" "from a import i as j\n" "from a import g as h\n" "from a import e as f\n" ) test_input = ( "import a\n" "from a import *\n" "from a import z, x, y\n" "from a import b\n" "from a import w\n" ) test_output = isort.code( code=test_input, combine_star=True, combine_as_imports=True, force_single_line=False, no_inline_sort=False, ) assert test_output == "import a\nfrom a import *\n" test_output = isort.code( code=test_input, combine_star=True, combine_as_imports=False, force_single_line=True, no_inline_sort=False, ) assert test_output == "import a\nfrom a import *\n" test_output = isort.code( code=test_input, combine_star=True, combine_as_imports=False, force_single_line=False, no_inline_sort=True, ) assert test_output == "import a\nfrom a import *\n" test_output = isort.code( code=test_input, combine_star=False, combine_as_imports=True, force_single_line=True, no_inline_sort=False, ) assert test_output == ( "import a\n" "from a import *\n" "from a import b\n" "from a import w\n" "from a import x\n" "from a import y\n" "from a import z\n" ) test_input = ( "import a\n" "from a import *\n" "from a import b\n" "from a import b as d\n" "from a import b as c\n" "from a import z, x, y, w\n" "from a import i as j\n" "from a import g as h\n" "from a import e as f\n" ) test_output = isort.code( code=test_input, combine_star=False, combine_as_imports=True, force_single_line=False, no_inline_sort=True, ) assert test_output == ( "import a\n" "from a import *\n" "from a import b, b as d, b as c, z, x, y, w, i as j, g as h, e as f\n" ) test_output = isort.code( code=test_input, combine_star=False, combine_as_imports=False, force_single_line=True, no_inline_sort=True, ) assert test_output == ( "import a\n" "from a import *\n" "from a import b\n" "from a import b as c\n" "from a import b as d\n" "from a import e as f\n" "from a import g as h\n" "from a import i as j\n" "from a import w\n" "from a import x\n" "from a import y\n" "from a import z\n" ) test_input = ( "import a\n" "from a import *\n" "from a import z, x, y\n" "from a import b\n" "from a import w\n" ) test_output = isort.code( code=test_input, combine_star=True, combine_as_imports=True, force_single_line=True, no_inline_sort=False, ) assert test_output == "import a\nfrom a import *\n" def test_noqa_issue_679() -> None: """Test to ensure that NOQA notation is being observed as expected if honor_noqa is set to `True` """ test_input = """ import os import requestsss import zed # NOQA import ujson # NOQA import foo""" test_output = """ import os import foo import requestsss import ujson # NOQA import zed # NOQA """ test_output_honor_noqa = """ import os import foo import requestsss import zed # NOQA import ujson # NOQA """ assert isort.code(test_input) == test_output assert isort.code(test_input.lower()) == test_output.lower() assert isort.code(test_input, honor_noqa=True) == test_output_honor_noqa assert isort.code(test_input.lower(), honor_noqa=True) == test_output_honor_noqa.lower() def test_extract_multiline_output_wrap_setting_from_a_config_file(tmp_path: Path) -> None: editorconfig_contents = ["root = true", " [*.py]", "multi_line_output = 5"] config_file = tmp_path / ".editorconfig" config_file.write_text("\n".join(editorconfig_contents)) config = Config(settings_path=str(tmp_path)) assert config.multi_line_output == WrapModes.VERTICAL_GRID_GROUPED def test_ensure_support_for_non_typed_but_cased_alphabetic_sort_issue_890() -> None: test_input = ( "from pkg import BALL\n" "from pkg import RC\n" "from pkg import Action\n" "from pkg import Bacoo\n" "from pkg import RCNewCode\n" "from pkg import actual\n" "from pkg import rc\n" "from pkg import recorder\n" ) expected_output = ( "from pkg import Action\n" "from pkg import BALL\n" "from pkg import Bacoo\n" "from pkg import RC\n" "from pkg import RCNewCode\n" "from pkg import actual\n" "from pkg import rc\n" "from pkg import recorder\n" ) assert ( isort.code( code=test_input, case_sensitive=True, order_by_type=False, force_single_line=True ) == expected_output ) def test_to_ensure_empty_line_not_added_to_file_start_issue_889() -> None: test_input = "# comment\nimport os\n# comment2\nimport sys\n" assert isort.code(test_input) == test_input def test_to_ensure_correctly_handling_of_whitespace_only_issue_811(capsys) -> None: test_input = ( "import os\n" "import sys\n" "\n" "\x0c\n" "def my_function():\n" ' print("hi")\n' ) isort.code(test_input, ignore_whitespace=True) out, err = capsys.readouterr() assert out == "" assert err == "" def test_standard_library_deprecates_user_issue_778() -> None: test_input = "import os\n\nimport user\n" assert isort.code(test_input) == test_input @pytest.mark.skipif(sys.platform == "win32", reason="does not run on windows") def test_settings_path_skip_issue_909(tmpdir) -> None: base_dir = tmpdir.mkdir("project") config_dir = base_dir.mkdir("conf") config_dir.join(".isort.cfg").write( "[isort]\n" "skip =\n" " file_to_be_skipped.py\n" "skip_glob =\n" " *glob_skip*\n" ) base_dir.join("file_glob_skip.py").write( "import os\n\n" 'print("Hello World")\n' "\nimport sys\nimport os\n" ) base_dir.join("file_to_be_skipped.py").write( "import os\n\n" 'print("Hello World")' "\nimport sys\nimport os\n" ) test_run_directory = os.getcwd() os.chdir(str(base_dir)) with pytest.raises(subprocess.CalledProcessError): # without the settings path provided: the command should not skip & identify errors subprocess.run(["isort", ".", "--check-only"], check=True) result = subprocess.run( ["isort", ".", "--check-only", "--settings-path=conf/.isort.cfg"], stdout=subprocess.PIPE, check=True, ) os.chdir(str(test_run_directory)) assert b"skipped 2" in result.stdout.lower() @pytest.mark.skipif(sys.platform == "win32", reason="does not run on windows") def test_skip_paths_issue_938(tmpdir) -> None: base_dir = tmpdir.mkdir("project") config_dir = base_dir.mkdir("conf") config_dir.join(".isort.cfg").write( "[isort]\n" "line_length = 88\n" "multi_line_output = 4\n" "lines_after_imports = 2\n" "skip_glob =\n" " migrations/**.py\n" ) base_dir.join("dont_skip.py").write("import os\n\n" 'print("Hello World")' "\nimport sys\n") migrations_dir = base_dir.mkdir("migrations") migrations_dir.join("file_glob_skip.py").write( "import os\n\n" 'print("Hello World")\n' "\nimport sys\n" ) test_run_directory = os.getcwd() os.chdir(str(base_dir)) result = subprocess.run( ["isort", "dont_skip.py", "migrations/file_glob_skip.py"], stdout=subprocess.PIPE, check=True, ) os.chdir(str(test_run_directory)) assert b"skipped" not in result.stdout.lower() os.chdir(str(base_dir)) result = subprocess.run( [ "isort", "--filter-files", "--settings-path=conf/.isort.cfg", "dont_skip.py", "migrations/file_glob_skip.py", ], stdout=subprocess.PIPE, check=True, ) os.chdir(str(test_run_directory)) assert b"skipped 1" in result.stdout.lower() def test_failing_file_check_916() -> None: test_input = ( "#!/usr/bin/env python\n" "# -*- coding: utf-8 -*-\n" "from __future__ import unicode_literals\n" ) expected_output = ( "#!/usr/bin/env python\n" "# -*- coding: utf-8 -*-\n" "# FUTURE\n" "from __future__ import unicode_literals\n" ) settings = { "import_heading_future": "FUTURE", "sections": ["FUTURE", "STDLIB", "NORDIGEN", "FIRSTPARTY", "THIRDPARTY", "LOCALFOLDER"], "indent": " ", "multi_line_output": 3, "lines_after_imports": 2, } # type: Dict[str, Any] assert isort.code(test_input, **settings) == expected_output assert isort.code(expected_output, **settings) == expected_output assert api.check_code_string(expected_output, **settings) def test_import_heading_issue_905() -> None: config = { "import_heading_stdlib": "Standard library imports", "import_heading_thirdparty": "Third party imports", "import_heading_firstparty": "Local imports", "known_third_party": ["numpy"], "known_first_party": ["oklib"], } # type: Dict[str, Any] test_input = ( "# Standard library imports\n" "from os import path as osp\n" "\n" "# Third party imports\n" "import numpy as np\n" "\n" "# Local imports\n" "from oklib.plot_ok import imagesc\n" ) assert isort.code(test_input, **config) == test_input def test_isort_keeps_comments_issue_691() -> None: test_input = ( "import os\n" "# This will make sure the app is always imported when\n" "# Django starts so that shared_task will use this app.\n" "from .celery import app as celery_app # noqa\n" "\n" "PROJECT_DIR = os.path.dirname(os.path.abspath(__file__))\n" "\n" "def path(*subdirectories):\n" " return os.path.join(PROJECT_DIR, *subdirectories)\n" ) expected_output = ( "import os\n" "\n" "# This will make sure the app is always imported when\n" "# Django starts so that shared_task will use this app.\n" "from .celery import app as celery_app # noqa\n" "\n" "PROJECT_DIR = os.path.dirname(os.path.abspath(__file__))\n" "\n" "def path(*subdirectories):\n" " return os.path.join(PROJECT_DIR, *subdirectories)\n" ) assert isort.code(test_input) == expected_output def test_isort_multiline_with_tab_issue_1714() -> None: test_input = "from sys \\ \n" "\timport version\n" "print(version)\n" expected_output = "from sys import version\n" "\n" "print(version)\n" assert isort.code(test_input) == expected_output def test_isort_ensures_blank_line_between_import_and_comment() -> None: config = { "ensure_newline_before_comments": True, "lines_between_sections": 0, "known_one": ["one"], "known_two": ["two"], "known_three": ["three"], "known_four": ["four"], "sections": [ "FUTURE", "STDLIB", "FIRSTPARTY", "THIRDPARTY", "LOCALFOLDER", "ONE", "TWO", "THREE", "FOUR", ], } # type: Dict[str, Any] test_input = ( "import os\n" "# noinspection PyUnresolvedReferences\n" "import one.a\n" "# noinspection PyUnresolvedReferences\n" "import one.b\n" "# noinspection PyUnresolvedReferences\n" "import two.a as aa\n" "# noinspection PyUnresolvedReferences\n" "import two.b as bb\n" "# noinspection PyUnresolvedReferences\n" "from three.a import a\n" "# noinspection PyUnresolvedReferences\n" "from three.b import b\n" "# noinspection PyUnresolvedReferences\n" "from four.a import a as aa\n" "# noinspection PyUnresolvedReferences\n" "from four.b import b as bb\n" ) expected_output = ( "import os\n" "\n" "# noinspection PyUnresolvedReferences\n" "import one.a\n" "\n" "# noinspection PyUnresolvedReferences\n" "import one.b\n" "\n" "# noinspection PyUnresolvedReferences\n" "import two.a as aa\n" "\n" "# noinspection PyUnresolvedReferences\n" "import two.b as bb\n" "\n" "# noinspection PyUnresolvedReferences\n" "from three.a import a\n" "\n" "# noinspection PyUnresolvedReferences\n" "from three.b import b\n" "\n" "# noinspection PyUnresolvedReferences\n" "from four.a import a as aa\n" "\n" "# noinspection PyUnresolvedReferences\n" "from four.b import b as bb\n" ) assert isort.code(test_input, **config) == expected_output def test_pyi_formatting_issue_942(tmpdir) -> None: test_input = "import os\n\n\ndef my_method():\n" expected_py_output = test_input.splitlines() expected_pyi_output = "import os\n\ndef my_method():\n".splitlines() assert isort.code(test_input).splitlines() == expected_py_output assert isort.code(test_input, extension="pyi").splitlines() == expected_pyi_output source_py = tmpdir.join("source.py") source_py.write(test_input) assert ( isort.code(code=Path(source_py).read_text(), file_path=Path(source_py)).splitlines() == expected_py_output ) source_pyi = tmpdir.join("source.pyi") source_pyi.write(test_input) assert ( isort.code( code=Path(source_pyi).read_text(), extension="pyi", file_path=Path(source_pyi) ).splitlines() == expected_pyi_output ) # Ensure it works for direct file API as well (see: issue #1284) source_pyi = tmpdir.join("source.pyi") source_pyi.write(test_input) api.sort_file(Path(source_pyi)) assert source_pyi.read().splitlines() == expected_pyi_output def test_move_class_issue_751() -> None: test_input = ( "# -*- coding: utf-8 -*-" "\n" "# Define your item pipelines here" "#" "# Don't forget to add your pipeline to the ITEM_PIPELINES setting" "# See: https://doc.scrapy.org/en/latest/topics/item-pipeline.html" "from datetime import datetime" "from .items import WeiboMblogItem" "\n" "class WeiboMblogPipeline(object):" " def process_item(self, item, spider):" " if isinstance(item, WeiboMblogItem):" " item = self._process_item(item, spider)" " return item" "\n" " def _process_item(self, item, spider):" " item['inserted_at'] = datetime.now()" " return item" "\n" ) assert isort.code(test_input) == test_input def test_python_version() -> None: from isort.main import parse_args # test that the py_version can be added as flag args = parse_args(["--py=27"]) assert args["py_version"] == "27" args = parse_args(["--python-version=3"]) assert args["py_version"] == "3" test_input = "import os\n\nimport user\n" assert isort.code(test_input, py_version="3") == test_input # user is part of the standard library in python 2 output_python_2 = "import os\nimport user\n" assert isort.code(test_input, py_version="27") == output_python_2 test_input = "import os\nimport xml" print(isort.code(test_input, py_version="all")) def test_isort_with_single_character_import() -> None: """Tests to ensure isort handles single capatilized single character imports as class objects by default See Issue #376: https://github.com/pycqa/isort/issues/376 """ test_input = "from django.db.models import CASCADE, SET_NULL, Q\n" assert isort.code(test_input) == test_input def test_isort_nested_imports() -> None: """Ensure imports in a nested block get sorted correctly""" test_input = """ def import_test(): import sys import os # my imports from . import def from . import abc return True """ assert ( isort.code(test_input) == """ def import_test(): import os import sys # my imports from . import abc, def return True """ ) def test_isort_off() -> None: """Test that isort can be turned on and off at will using comments""" test_input = """import os # isort: off import sys import os # isort: on from . import local """ assert isort.code(test_input) == test_input def test_isort_split() -> None: """Test the ability to split isort import sections""" test_input = """import os import sys # isort: split import os import sys """ assert isort.code(test_input) == test_input test_input = """import c import b # isort: split import a import c """ assert isort.code(test_input) == test_input def test_comment_look_alike(): """Test to ensure isort will handle what looks like a single line comment at the end of a multi-line comment. """ test_input = ''' """This is a multi-line comment ending with what appears to be a single line comment # Single Line Comment""" import sys import os ''' assert ( isort.code(test_input) == ''' """This is a multi-line comment ending with what appears to be a single line comment # Single Line Comment""" import os import sys ''' ) def test_cimport_support(): """Test to ensure cimports (Cython style imports) work""" test_input = """ import os import sys import cython import platform import traceback import time import types import re import copy import inspect # used by JavascriptBindings.__SetObjectMethods() import urllib import json import datetime import random if sys.version_info.major == 2: import urlparse else: from urllib import parse as urlparse if sys.version_info.major == 2: from urllib import pathname2url as urllib_pathname2url else: from urllib.request import pathname2url as urllib_pathname2url from cpython.version cimport PY_MAJOR_VERSION import weakref # We should allow multiple string types: str, unicode, bytes. # PyToCefString() can handle them all. # Important: # If you set it to basestring, Cython will accept exactly(!) # str/unicode in Py2 and str in Py3. This won't work in Py3 # as we might want to pass bytes as well. Also it will # reject string subtypes, so using it in publi API functions # would be a bad idea. ctypedef object py_string # You can't use "void" along with cpdef function returning None, it is planned to be # added to Cython in the future, creating this virtual type temporarily. If you # change it later to "void" then don't forget to add "except *". ctypedef object py_void ctypedef long WindowHandle from cpython cimport PyLong_FromVoidPtr from cpython cimport bool as py_bool from libcpp cimport bool as cpp_bool from libcpp.map cimport map as cpp_map from multimap cimport multimap as cpp_multimap from libcpp.pair cimport pair as cpp_pair from libcpp.vector cimport vector as cpp_vector from libcpp.string cimport string as cpp_string from wstring cimport wstring as cpp_wstring from libc.string cimport strlen from libc.string cimport memcpy # preincrement and dereference must be "as" otherwise not seen. from cython.operator cimport preincrement as preinc, dereference as deref # from cython.operator cimport address as addr # Address of an c++ object? from libc.stdlib cimport calloc, malloc, free from libc.stdlib cimport atoi # When pyx file cimports * from a pxd file and that pxd cimports * from another pxd # then these names will be visible in pyx file. # Circular imports are allowed in form "cimport ...", but won't work if you do # "from ... cimport *", this is important to know in pxd files. from libc.stdint cimport uint64_t from libc.stdint cimport uintptr_t cimport ctime IF UNAME_SYSNAME == "Windows": from windows cimport * from dpi_aware_win cimport * ELIF UNAME_SYSNAME == "Linux": from linux cimport * ELIF UNAME_SYSNAME == "Darwin": from mac cimport * from cpp_utils cimport * from task cimport * from cef_string cimport * cdef extern from *: ctypedef CefString ConstCefString "const CefString" from cef_types_wrappers cimport * from cef_task cimport * from cef_runnable cimport * from cef_platform cimport * from cef_ptr cimport * from cef_app cimport * from cef_browser cimport * cimport cef_browser_static from cef_client cimport * from client_handler cimport * from cef_frame cimport * # cannot cimport *, that would cause name conflicts with constants. cimport cef_types ctypedef cef_types.cef_paint_element_type_t PaintElementType ctypedef cef_types.cef_jsdialog_type_t JSDialogType from cef_types cimport CefKeyEvent from cef_types cimport CefMouseEvent from cef_types cimport CefScreenInfo # cannot cimport *, name conflicts IF UNAME_SYSNAME == "Windows": cimport cef_types_win ELIF UNAME_SYSNAME == "Darwin": cimport cef_types_mac ELIF UNAME_SYSNAME == "Linux": cimport cef_types_linux from cef_time cimport * from cef_drag cimport * import os IF CEF_VERSION == 1: from cef_v8 cimport * cimport cef_v8_static cimport cef_v8_stack_trace from v8function_handler cimport * from cef_request_cef1 cimport * from cef_web_urlrequest_cef1 cimport * cimport cef_web_urlrequest_static_cef1 from web_request_client_cef1 cimport * from cef_stream cimport * cimport cef_stream_static from cef_response_cef1 cimport * from cef_stream cimport * from cef_content_filter cimport * from content_filter_handler cimport * from cef_download_handler cimport * from download_handler cimport * from cef_cookie_cef1 cimport * cimport cef_cookie_manager_namespace from cookie_visitor cimport * from cef_render_handler cimport * from cef_drag_data cimport * IF UNAME_SYSNAME == "Windows": IF CEF_VERSION == 1: from http_authentication cimport * IF CEF_VERSION == 3: from cef_values cimport * from cefpython_app cimport * from cef_process_message cimport * from cef_web_plugin_cef3 cimport * from cef_request_handler_cef3 cimport * from cef_request_cef3 cimport * from cef_cookie_cef3 cimport * from cef_string_visitor cimport * cimport cef_cookie_manager_namespace from cookie_visitor cimport * from string_visitor cimport * from cef_callback_cef3 cimport * from cef_response_cef3 cimport * from cef_resource_handler_cef3 cimport * from resource_handler_cef3 cimport * from cef_urlrequest_cef3 cimport * from web_request_client_cef3 cimport * from cef_command_line cimport * from cef_request_context cimport * from cef_request_context_handler cimport * from request_context_handler cimport * from cef_jsdialog_handler cimport * """ expected_output = """ import copy import datetime import inspect # used by JavascriptBindings.__SetObjectMethods() import json import os import platform import random import re import sys import time import traceback import types import urllib import cython if sys.version_info.major == 2: import urlparse else: from urllib import parse as urlparse if sys.version_info.major == 2: from urllib import pathname2url as urllib_pathname2url else: from urllib.request import pathname2url as urllib_pathname2url from cpython.version cimport PY_MAJOR_VERSION import weakref # We should allow multiple string types: str, unicode, bytes. # PyToCefString() can handle them all. # Important: # If you set it to basestring, Cython will accept exactly(!) # str/unicode in Py2 and str in Py3. This won't work in Py3 # as we might want to pass bytes as well. Also it will # reject string subtypes, so using it in publi API functions # would be a bad idea. ctypedef object py_string # You can't use "void" along with cpdef function returning None, it is planned to be # added to Cython in the future, creating this virtual type temporarily. If you # change it later to "void" then don't forget to add "except *". ctypedef object py_void ctypedef long WindowHandle cimport ctime from cpython cimport PyLong_FromVoidPtr from cpython cimport bool as py_bool # preincrement and dereference must be "as" otherwise not seen. from cython.operator cimport dereference as deref from cython.operator cimport preincrement as preinc from libc.stdint cimport uint64_t, uintptr_t from libc.stdlib cimport atoi, calloc, free, malloc from libc.string cimport memcpy, strlen from libcpp cimport bool as cpp_bool from libcpp.map cimport map as cpp_map from libcpp.pair cimport pair as cpp_pair from libcpp.string cimport string as cpp_string from libcpp.vector cimport vector as cpp_vector from multimap cimport multimap as cpp_multimap from wstring cimport wstring as cpp_wstring # from cython.operator cimport address as addr # Address of an c++ object? # When pyx file cimports * from a pxd file and that pxd cimports * from another pxd # then these names will be visible in pyx file. # Circular imports are allowed in form "cimport ...", but won't work if you do # "from ... cimport *", this is important to know in pxd files. IF UNAME_SYSNAME == "Windows": from dpi_aware_win cimport * from windows cimport * ELIF UNAME_SYSNAME == "Linux": from linux cimport * ELIF UNAME_SYSNAME == "Darwin": from mac cimport * from cef_string cimport * from cpp_utils cimport * from task cimport * cdef extern from *: ctypedef CefString ConstCefString "const CefString" cimport cef_browser_static # cannot cimport *, that would cause name conflicts with constants. cimport cef_types from cef_app cimport * from cef_browser cimport * from cef_client cimport * from cef_frame cimport * from cef_platform cimport * from cef_ptr cimport * from cef_runnable cimport * from cef_task cimport * from cef_types_wrappers cimport * from client_handler cimport * ctypedef cef_types.cef_paint_element_type_t PaintElementType ctypedef cef_types.cef_jsdialog_type_t JSDialogType from cef_types cimport CefKeyEvent, CefMouseEvent, CefScreenInfo # cannot cimport *, name conflicts IF UNAME_SYSNAME == "Windows": cimport cef_types_win ELIF UNAME_SYSNAME == "Darwin": cimport cef_types_mac ELIF UNAME_SYSNAME == "Linux": cimport cef_types_linux from cef_drag cimport * from cef_time cimport * import os IF CEF_VERSION == 1: cimport cef_cookie_manager_namespace cimport cef_stream_static cimport cef_v8_stack_trace cimport cef_v8_static cimport cef_web_urlrequest_static_cef1 from cef_content_filter cimport * from cef_cookie_cef1 cimport * from cef_download_handler cimport * from cef_drag_data cimport * from cef_render_handler cimport * from cef_request_cef1 cimport * from cef_response_cef1 cimport * from cef_stream cimport * from cef_v8 cimport * from cef_web_urlrequest_cef1 cimport * from content_filter_handler cimport * from cookie_visitor cimport * from download_handler cimport * from v8function_handler cimport * from web_request_client_cef1 cimport * IF UNAME_SYSNAME == "Windows": IF CEF_VERSION == 1: from http_authentication cimport * IF CEF_VERSION == 3: cimport cef_cookie_manager_namespace from cef_callback_cef3 cimport * from cef_command_line cimport * from cef_cookie_cef3 cimport * from cef_jsdialog_handler cimport * from cef_process_message cimport * from cef_request_cef3 cimport * from cef_request_context cimport * from cef_request_context_handler cimport * from cef_request_handler_cef3 cimport * from cef_resource_handler_cef3 cimport * from cef_response_cef3 cimport * from cef_string_visitor cimport * from cef_urlrequest_cef3 cimport * from cef_values cimport * from cef_web_plugin_cef3 cimport * from cefpython_app cimport * from cookie_visitor cimport * from request_context_handler cimport * from resource_handler_cef3 cimport * from string_visitor cimport * from web_request_client_cef3 cimport * """ assert isort.code(test_input).strip() == expected_output.strip() assert isort.code(test_input, old_finders=True).strip() == expected_output.strip() def test_cdef_support(): assert ( isort.code( code=""" from cpython.version cimport PY_MAJOR_VERSION cdef extern from *: ctypedef CefString ConstCefString "const CefString" """ ) == """ from cpython.version cimport PY_MAJOR_VERSION cdef extern from *: ctypedef CefString ConstCefString "const CefString" """ ) assert ( isort.code( code=""" from cpython.version cimport PY_MAJOR_VERSION cpdef extern from *: ctypedef CefString ConstCefString "const CefString" """ ) == """ from cpython.version cimport PY_MAJOR_VERSION cpdef extern from *: ctypedef CefString ConstCefString "const CefString" """ ) def test_top_level_import_order() -> None: test_input = ( "from rest_framework import throttling, viewsets\n" "from rest_framework.authentication import TokenAuthentication\n" ) assert isort.code(test_input, force_sort_within_sections=True) == test_input def test_noqa_issue_1065() -> None: test_input = """ # # USER SIGNALS # from flask_login import user_logged_in, user_logged_out # noqa from flask_security.signals import ( # noqa password_changed as user_reset_password, # noqa user_confirmed, # noqa user_registered, # noqa ) # noqa from flask_principal import identity_changed as user_identity_changed # noqa """ expected_output = """ # # USER SIGNALS # from flask_login import user_logged_in, user_logged_out # noqa from flask_principal import identity_changed as user_identity_changed # noqa from flask_security.signals import password_changed as user_reset_password # noqa from flask_security.signals import user_confirmed # noqa from flask_security.signals import user_registered # noqa """ assert isort.code(test_input, line_length=100) == expected_output test_input_2 = """ # # USER SIGNALS # from flask_login import user_logged_in, user_logged_out # noqa from flask_security.signals import ( password_changed as user_reset_password, # noqa user_confirmed, # noqa user_registered, # noqa ) from flask_principal import identity_changed as user_identity_changed # noqa """ assert isort.code(test_input_2, line_length=100) == expected_output def test_single_line_exclusions(): test_input = """ # start comment from os import path, system from typing import List, TypeVar """ expected_output = """ # start comment from os import path from os import system from typing import List, TypeVar """ assert ( isort.code(code=test_input, force_single_line=True, single_line_exclusions=("typing",)) == expected_output ) def test_nested_comment_handling(): test_input = """ if True: import foo # comment for bar """ assert isort.code(test_input) == test_input # If comments appear inside import sections at same indentation they can be re-arranged. test_input = """ if True: import sys # os import import os """ expected_output = """ if True: # os import import os import sys """ assert isort.code(test_input) == expected_output # Comments shouldn't be unexpectedly rearranged. See issue #1090. test_input = """ def f(): # comment 1 # comment 2 # comment 3 # comment 4 from a import a from b import b """ assert isort.code(test_input) == test_input # Whitespace shouldn't be adjusted for nested imports. See issue #1090. test_input = """ try: import foo except ImportError: import bar """ assert isort.code(test_input) == test_input def test_comments_top_of_file(): """Test to ensure comments at top of file are correctly handled. See issue #1091.""" test_input = """# comment 1 # comment 2 # comment 3 # comment 4 from foo import * """ assert isort.code(test_input) == test_input test_input = """# -*- coding: utf-8 -*- # Define your item pipelines here # # Don't forget to add your pipeline to the ITEM_PIPELINES setting # See: https://doc.scrapy.org/en/latest/topics/item-pipeline.html from datetime import datetime from .items import WeiboMblogItem class WeiboMblogPipeline(object): def process_item(self, item, spider): if isinstance(item, WeiboMblogItem): item = self._process_item(item, spider) return item def _process_item(self, item, spider): item['inserted_at'] = datetime.now() return item """ assert isort.code(test_input) == test_input def test_multiple_aliases(): """Test to ensure isort will retain multiple aliases. See issue #1037""" test_input = """import datetime import datetime as datetime import datetime as dt import datetime as dt2 """ assert isort.code(code=test_input) == test_input def test_parens_in_comment(): """Test to ensure isort can handle parens placed in comments. See issue #1103""" test_input = """from foo import ( # (some text in brackets) bar, ) """ expected_output = "from foo import bar # (some text in brackets)\n" assert isort.code(test_input) == expected_output def test_as_imports_mixed(): """Test to ensure as imports can be mixed with non as. See issue #908""" test_input = """from datetime import datetime import datetime.datetime as dt """ expected_output = """import datetime.datetime as dt from datetime import datetime """ assert isort.code(test_input) == expected_output def test_no_sections_with_future(): """Test to ensure no_sections works with future. See issue #807""" test_input = """from __future__ import print_function import os """ expected_output = """from __future__ import print_function import os """ assert isort.code(test_input, no_sections=True) == expected_output def test_no_sections_with_as_import(): """Test to ensure no_sections work with as import.""" test_input = """import oumpy as np import sympy """ assert isort.code(test_input, no_sections=True) == test_input def test_no_lines_too_long(): """Test to ensure no lines end up too long. See issue: #1015""" test_input = """from package1 import first_package, \ second_package from package2 import \\ first_package """ expected_output = """from package1 import \\ first_package, \\ second_package from package2 import \\ first_package """ assert isort.code(test_input, line_length=25, multi_line_output=2) == expected_output def test_python_future_category(): """Test to ensure a manual python future category will work as needed to install aliases see: Issue #1005 """ test_input = """from __future__ import absolute_import # my future comment from future import standard_library standard_library.install_aliases() import os import re import time from logging.handlers import SysLogHandler from builtins import len, object, str from katlogger import log_formatter, log_rollover from .query_elastic import QueryElastic """ expected_output = """from __future__ import absolute_import # my future comment from future import standard_library standard_library.install_aliases() # Python Standard Library import os import re import time from builtins import len, object, str from logging.handlers import SysLogHandler # CAM Packages from katlogger import log_formatter, log_rollover # Explicitly Local from .query_elastic import QueryElastic """ assert ( isort.code( code=test_input, force_grid_wrap=False, include_trailing_comma=True, indent=4, line_length=90, multi_line_output=3, lines_between_types=1, sections=[ "FUTURE_LIBRARY", "FUTURE_THIRDPARTY", "STDLIB", "THIRDPARTY", "FIRSTPARTY", "LOCALFOLDER", ], import_heading_stdlib="Python Standard Library", import_heading_thirdparty="Third Library", import_heading_firstparty="CAM Packages", import_heading_localfolder="Explicitly Local", known_first_party=["katlogger"], known_future_thirdparty=["future"], ) == expected_output ) def test_combine_star_comments_above(): input_text = """from __future__ import absolute_import # my future comment from future import *, something """ expected_output = """from __future__ import absolute_import # my future comment from future import * """ assert isort.code(input_text, combine_star=True) == expected_output def test_deprecated_settings(): """Test to ensure isort warns when deprecated settings are used, but doesn't fail to run""" with pytest.warns(UserWarning): assert isort.code("hi", not_skip=True) def test_deprecated_settings_no_warn_in_quiet_mode(recwarn): """Test to ensure isort does NOT warn in quiet mode even though settings are deprecated""" assert isort.code("hi", not_skip=True, quiet=True) assert not recwarn def test_only_sections() -> None: """Test to ensure that the within sections relative position of imports are maintained""" test_input = ( "import sys\n" "\n" "import numpy as np\n" "\n" "import os\n" "from os import path as ospath\n" "\n" "import pandas as pd\n" "\n" "import math\n" "import .views\n" "from collections import defaultdict\n" ) assert ( isort.code(test_input, only_sections=True) == ( "import sys\n" "import os\n" "import math\n" "from os import path as ospath\n" "from collections import defaultdict\n" "\n" "import numpy as np\n" "import pandas as pd\n" "\n" "import .views\n" ) == isort.code(test_input, only_sections=True, force_single_line=True) ) # test to ensure that from_imports remain intact with only_sections test_input = "from foo import b, a, c\n" assert isort.code(test_input, only_sections=True) == test_input def test_combine_straight_imports() -> None: """Tests to ensure that combine_straight_imports works correctly""" test_input = ( "import os\n" "import sys\n" "# this is a comment\n" "import math # inline comment\n" ) assert isort.code(test_input, combine_straight_imports=True) == ( "# this is a comment\n" "import math, os, sys # inline comment\n" ) # test to ensure that combine_straight_import works with only_sections test_input = "import sys, os\n" "import a\n" "import math\n" "import b\n" assert isort.code(test_input, combine_straight_imports=True, only_sections=True) == ( "import sys, os, math\n" "\n" "import a, b\n" ) def test_find_imports_in_code() -> None: test_input = ( "import first_straight\n" "\n" "import second_straight\n" "from first_from import first_from_function_1, first_from_function_2\n" "import bad_name as good_name\n" "from parent.some_bad_defs import bad_name_1 as ok_name_1, bad_name_2 as ok_name_2\n" "\n" "# isort: list\n" "__all__ = ['b', 'c', 'a']\n" "\n" "def bla():\n" " import needed_in_bla_2\n" "\n" "\n" " import needed_in_bla\n" " pass" "\n" "def bla_bla():\n" " import needed_in_bla_bla\n" "\n" " #import not_really_an_import\n" " pass" "\n" "import needed_in_end\n" ) identified_imports = list(map(str, api.find_imports_in_code(test_input))) assert identified_imports == [ ":1 import first_straight", ":3 import second_straight", ":4 from first_from import first_from_function_1", ":4 from first_from import first_from_function_2", ":5 import bad_name as good_name", ":6 from parent.some_bad_defs import bad_name_1 as ok_name_1", ":6 from parent.some_bad_defs import bad_name_2 as ok_name_2", ":12 indented import needed_in_bla_2", ":15 indented import needed_in_bla", ":18 indented import needed_in_bla_bla", ":22 import needed_in_end", ] def test_find_imports_in_stream() -> None: """Ensure that find_imports_in_stream can work with nonseekable streams like STDOUT""" class NonSeekableTestStream(StringIO): def seek(self, offset: int, whence: int = os.SEEK_SET, /) -> int: raise OSError("Stream is not seekable") def seekable(self): return False test_input = NonSeekableTestStream("import m2\n" "import m1\n" "not_import = 7") identified_imports = list(map(str, api.find_imports_in_stream(test_input))) assert identified_imports == [":1 import m2", ":2 import m1"] def test_split_on_trailing_comma() -> None: test_input = "from lib import (a, b, c,)" expected_output = """from lib import ( a, b, c, ) """ output = isort.code(test_input, split_on_trailing_comma=True) assert output == expected_output output = isort.code(expected_output, split_on_trailing_comma=True) assert output == expected_output def test_split_on_trailing_comma_wih_as() -> None: test_input = "from lib import (a as b,)" expected_output = """from lib import a as b """ output = isort.code(test_input, split_on_trailing_comma=True) assert output == expected_output output = isort.code(expected_output, split_on_trailing_comma=True) assert output == expected_output def test_infinite_loop_in_unmatched_parenthesis() -> None: test_input = "from os import (" # ensure a syntax error is raised for unmatched parenthesis with pytest.raises(ExistingSyntaxErrors): isort.code(test_input) test_input = """from os import ( path, walk ) """ # ensure other cases are handled correctly assert isort.code(test_input) == "from os import path, walk\n" def test_reexport() -> None: test_input = """__all__ = ('foo', 'bar') """ expd_output = """__all__ = ('bar', 'foo') """ assert isort.code(test_input, config=Config(sort_reexports=True)) == expd_output def test_reexport_leave_alone_if_not_enabled() -> None: test_input = """__all__ = ('foo', 'bar') """ assert isort.code(test_input) == test_input def test_reexport_multiline() -> None: test_input = """__all__ = ( 'foo', 'bar', ) """ expd_output = """__all__ = ('bar', 'foo') """ assert isort.code(test_input, config=Config(sort_reexports=True)) == expd_output def test_reexport_list() -> None: test_input = """__all__ = ['foo', 'bar'] """ expd_output = """__all__ = ['bar', 'foo'] """ assert isort.code(test_input, config=Config(sort_reexports=True)) == expd_output def test_reexport_set() -> None: test_input = """__all__ = {'foo', 'bar'} """ expd_output = """__all__ = {'bar', 'foo'} """ assert isort.code(test_input, config=Config(sort_reexports=True)) == expd_output def test_reexport_bare() -> None: test_input = """__all__ = 'foo', 'bar' """ expd_output = """__all__ = ('bar', 'foo') """ assert isort.code(test_input, config=Config(sort_reexports=True)) == expd_output def test_reexport_no_spaces() -> None: test_input = """__all__=('foo', 'bar') """ expd_output = """__all__ = ('bar', 'foo') """ assert isort.code(test_input, config=Config(sort_reexports=True)) == expd_output def test_reexport_not_first_line() -> None: test_input = """import random __all__ = ('foo', 'bar') """ expd_output = """import random __all__ = ('bar', 'foo') """ assert isort.code(test_input, config=Config(sort_reexports=True)) == expd_output def test_reexport_not_last_line() -> None: test_input = """__all__ = ('foo', 'bar') meme = "rickroll" """ expd_output = """__all__ = ('bar', 'foo') meme = "rickroll" """ assert isort.code(test_input, config=Config(sort_reexports=True)) == expd_output def test_reexport_multiline_import() -> None: test_input = """from m import ( bar, foo, ) __all__ = [ "foo", "bar", ] """ expd_output = """from m import bar, foo __all__ = ['bar', 'foo'] """ assert isort.code(test_input, config=Config(sort_reexports=True)) == expd_output def test_reexport_multiline_in_center() -> None: test_input = """from m import ( bar, foo, ) __all__ = [ "foo", "bar", ] test """ expd_output = """from m import bar, foo __all__ = ['bar', 'foo'] test """ assert isort.code(test_input, config=Config(sort_reexports=True)) == expd_output def test_reexport_multiline_long_rollback() -> None: test_input = """from m import foo, bar __all__ = [ "foo", "bar", ] test """ expd_output = """from m import bar, foo __all__ = ['bar', 'foo'] test """ assert isort.code(test_input, config=Config(sort_reexports=True)) == expd_output isort-6.0.1/tests/unit/test_literal.py0000644000000000000000000000157213615410400014771 0ustar00import pytest import isort.literal from isort import exceptions def test_value_mismatch(): with pytest.raises(exceptions.LiteralSortTypeMismatch): isort.literal.assignment("x = [1, 2, 3]", "set", "py") def test_invalid_syntax(): with pytest.raises(exceptions.LiteralParsingFailure): isort.literal.assignment("x = [1, 2, 3", "list", "py") def test_invalid_sort_type(): with pytest.raises(ValueError, match="Trying to sort using an undefined sort_type. Defined"): isort.literal.assignment("x = [1, 2, 3", "tuple-list-not-exist", "py") def test_value_assignment_assignments(): assert isort.literal.assignment("b = 1\na = 2\n", "assignments", "py") == "a = 2\nb = 1\n" def test_assignments_invalid_section(): with pytest.raises(exceptions.AssignmentsFormatMismatch): isort.literal.assignment("\n\nx = 1\nx++", "assignments", "py") isort-6.0.1/tests/unit/test_main.py0000644000000000000000000010342213615410400014256 0ustar00import json import os import pathlib import shutil import subprocess from datetime import datetime import pytest from hypothesis import given from hypothesis import strategies as st from isort import main from isort._version import __version__ from isort.exceptions import InvalidSettingsPath from isort.settings import DEFAULT_CONFIG, Config from .utils import as_stream from io import BytesIO, TextIOWrapper from typing import TYPE_CHECKING, Any if TYPE_CHECKING: WrapModes: Any else: from isort.wrap_modes import WrapModes @given( file_name=st.text(), config=st.builds(Config), check=st.booleans(), ask_to_apply=st.booleans(), write_to_stdout=st.booleans(), ) def test_fuzz_sort_imports(file_name, config, check, ask_to_apply, write_to_stdout): main.sort_imports( file_name=file_name, config=config, check=check, ask_to_apply=ask_to_apply, write_to_stdout=write_to_stdout, ) def test_sort_imports(tmpdir): tmp_file = tmpdir.join("file.py") tmp_file.write("import os, sys\n") assert main.sort_imports(str(tmp_file), DEFAULT_CONFIG, check=True).incorrectly_sorted # type: ignore # noqa main.sort_imports(str(tmp_file), DEFAULT_CONFIG) assert not main.sort_imports(str(tmp_file), DEFAULT_CONFIG, check=True).incorrectly_sorted # type: ignore # noqa skip_config = Config(skip=["file.py"]) assert main.sort_imports( # type: ignore str(tmp_file), config=skip_config, check=True, disregard_skip=False ).skipped assert main.sort_imports(str(tmp_file), config=skip_config, disregard_skip=False).skipped # type: ignore # noqa def test_sort_imports_error_handling(tmpdir, mocker, capsys): tmp_file = tmpdir.join("file.py") tmp_file.write("import os, sys\n") mocker.patch("isort.core.process").side_effect = IndexError("Example unhandled exception") with pytest.raises(IndexError): main.sort_imports(str(tmp_file), DEFAULT_CONFIG, check=True).incorrectly_sorted # type: ignore # noqa out, error = capsys.readouterr() assert "Unrecoverable exception thrown when parsing" in error def test_parse_args(): assert main.parse_args([]) == {} assert main.parse_args(["--multi-line", "1"]) == {"multi_line_output": WrapModes.VERTICAL} assert main.parse_args(["--multi-line", "GRID"]) == {"multi_line_output": WrapModes.GRID} assert main.parse_args(["--dont-order-by-type"]) == {"order_by_type": False} assert main.parse_args(["--dt"]) == {"order_by_type": False} assert main.parse_args(["--only-sections"]) == {"only_sections": True} assert main.parse_args(["--os"]) == {"only_sections": True} assert main.parse_args(["--om"]) == {"only_modified": True} assert main.parse_args(["--only-modified"]) == {"only_modified": True} assert main.parse_args(["--csi"]) == {"combine_straight_imports": True} assert main.parse_args(["--combine-straight-imports"]) == {"combine_straight_imports": True} assert main.parse_args(["--dont-follow-links"]) == {"follow_links": False} assert main.parse_args(["--overwrite-in-place"]) == {"overwrite_in_place": True} assert main.parse_args(["--from-first"]) == {"from_first": True} assert main.parse_args(["--resolve-all-configs"]) == {"resolve_all_configs": True} def test_ascii_art(capsys): main.main(["--version"]) out, error = capsys.readouterr() assert ( out == f""" _ _ (_) ___ ___ _ __| |_ | |/ _/ / _ \\/ '__ _/ | |\\__ \\/\\_\\/| | | |_ |_|\\___/\\___/\\_/ \\_/ isort your imports, so you don't have to. VERSION {__version__} """ ) assert error == "" def test_preconvert(): assert main._preconvert(frozenset([1, 1, 2])) == [1, 2] assert main._preconvert(WrapModes.GRID) == "GRID" assert main._preconvert(main._preconvert) == "_preconvert" with pytest.raises(TypeError): main._preconvert(datetime.now()) def test_show_files(capsys, tmpdir): tmpdir.join("a.py").write("import a") tmpdir.join("b.py").write("import b") # show files should list the files isort would sort main.main([str(tmpdir), "--show-files"]) out, error = capsys.readouterr() assert "a.py" in out assert "b.py" in out assert not error # can not be used for stream with pytest.raises(SystemExit): main.main(["-", "--show-files"]) # can not be used with show-config with pytest.raises(SystemExit): main.main([str(tmpdir), "--show-files", "--show-config"]) def test_missing_default_section(tmpdir): config_file = tmpdir.join(".isort.cfg") config_file.write( """ [settings] sections=MADEUP """ ) python_file = tmpdir.join("file.py") python_file.write("import os") with pytest.raises(SystemExit): main.main([str(python_file)]) def test_ran_against_root(): with pytest.raises(SystemExit): main.main(["/"]) def test_main(capsys, tmpdir): base_args = [ "-sp", str(tmpdir), "--virtual-env", str(tmpdir), "--src-path", str(tmpdir), ] tmpdir.mkdir(".git") # If nothing is passed in the quick guide is returned without erroring main.main([]) out, error = capsys.readouterr() assert main.QUICK_GUIDE in out assert not error # If no files are passed in but arguments are the quick guide is returned, alongside an error. with pytest.raises(SystemExit): main.main(base_args) out, error = capsys.readouterr() assert main.QUICK_GUIDE in out # Unless the config is requested, in which case it will be returned alone as JSON main.main([*base_args, "--show-config"]) out, error = capsys.readouterr() returned_config = json.loads(out) assert returned_config assert returned_config["virtual_env"] == str(tmpdir) # This should work even if settings path is not provided main.main(base_args[2:] + ["--show-config"]) out, error = capsys.readouterr() assert json.loads(out)["virtual_env"] == str(tmpdir) # This should raise an error if an invalid settings path is provided with pytest.raises(InvalidSettingsPath): main.main( base_args[2:] + ["--show-config"] + ["--settings-path", "/random-root-folder-that-cant-exist-right?"] ) # Should be able to set settings path to a file config_file = tmpdir.join(".isort.cfg") config_file.write( """ [settings] profile=hug verbose=true """ ) config_args = ["--settings-path", str(config_file)] main.main( [ *config_args, "--virtual-env", "/random-root-folder-that-cant-exist-right?", "--show-config", ] ) out, error = capsys.readouterr() assert json.loads(out)["profile"] == "hug" # Should be able to stream in content to sort input_content = TextIOWrapper( BytesIO( b""" import b import a """ ) ) main.main([*config_args, "-"], stdin=input_content) out, error = capsys.readouterr() assert ( out == f""" else-type place_module for b returned {DEFAULT_CONFIG.default_section} else-type place_module for a returned {DEFAULT_CONFIG.default_section} import a import b """ ) # Should be able to stream diff input_content = TextIOWrapper( BytesIO( b""" import b import a """ ) ) main.main([*config_args, "-", "--diff"], stdin=input_content) out, error = capsys.readouterr() assert not error assert "+" in out assert "-" in out assert "import a" in out assert "import b" in out # check should work with stdin input_content_check = TextIOWrapper( BytesIO( b""" import b import a """ ) ) with pytest.raises(SystemExit): main.main([*config_args, "-", "--check-only"], stdin=input_content_check) out, error = capsys.readouterr() assert error == "ERROR: Imports are incorrectly sorted and/or formatted.\n" # Should be able to run with just a file python_file = tmpdir.join("has_imports.py") python_file.write( """ import b import a """ ) main.main([str(python_file), "--filter-files", "--verbose"]) assert python_file.read().lstrip() == "import a\nimport b\n" # Add a file to skip should_skip = tmpdir.join("should_skip.py") should_skip.write("import nothing") main.main( [ str(python_file), str(should_skip), "--filter-files", "--verbose", "--skip", str(should_skip), ] ) # Should raise a system exit if check only, with broken file python_file.write( """ import b import a """ ) with pytest.raises(SystemExit): main.main( [ str(python_file), str(should_skip), "--filter-files", "--verbose", "--check-only", "--skip", str(should_skip), ] ) # Should have same behavior if full directory is skipped with pytest.raises(SystemExit): main.main( [str(tmpdir), "--filter-files", "--verbose", "--check-only", "--skip", str(should_skip)] ) # Nested files should be skipped without needing --filter-files nested_file = tmpdir.mkdir("nested_dir").join("skip.py") nested_file.write("import b;import a") python_file.write( """ import a import b """ ) main.main([str(tmpdir), "--extend-skip", "skip.py", "--check"]) # without filter options passed in should successfully sort files main.main([str(python_file), str(should_skip), "--verbose", "--atomic"]) # Should raise a system exit if all passed path is broken with pytest.raises(SystemExit): main.main(["not-exist", "--check-only"]) # Should not raise system exit if any of passed path is not broken main.main([str(python_file), "not-exist", "--verbose", "--check-only"]) out, error = capsys.readouterr() assert "Broken" in out # warnings should be displayed if old flags are used with pytest.warns(UserWarning): main.main([str(python_file), "--recursive", "-fss"]) # warnings should be displayed when streaming input is provided with old flags as well with pytest.warns(UserWarning): main.main(["-sp", str(config_file), "-"], stdin=input_content) def test_isort_filename_overrides(tmpdir, capsys): """Tests isorts available approaches for overriding filename and extension based behavior""" input_text = """ import b import a def function(): pass """ def build_input_content(): return as_stream(input_text) main.main(["-"], stdin=build_input_content()) out, error = capsys.readouterr() assert not error assert out == ( """ import a import b def function(): pass """ ) # if file is skipped it should output unchanged. main.main( ["-", "--filename", "x.py", "--skip", "x.py", "--filter-files"], stdin=build_input_content(), ) out, error = capsys.readouterr() assert not error assert out == ( """ import b import a def function(): pass """ ) main.main(["-", "--ext-format", "pyi"], stdin=build_input_content()) out, error = capsys.readouterr() assert not error assert out == ( """ import a import b def function(): pass """ ) tmp_file = tmpdir.join("tmp.pyi") tmp_file.write_text(input_text, encoding="utf8") main.main(["-", "--filename", str(tmp_file)], stdin=build_input_content()) out, error = capsys.readouterr() assert not error assert out == ( """ import a import b def function(): pass """ ) # setting a filename override when file is passed in as non-stream is not supported. with pytest.raises(SystemExit): main.main([str(tmp_file), "--filename", str(tmp_file)], stdin=build_input_content()) def test_isort_float_to_top_overrides(tmpdir, capsys): """Tests isorts supports overriding float to top from CLI""" test_input = """ import b def function(): pass import a """ config_file = tmpdir.join(".isort.cfg") config_file.write( """ [settings] float_to_top=True """ ) python_file = tmpdir.join("file.py") python_file.write(test_input) main.main([str(python_file)]) out, error = capsys.readouterr() assert not error assert "Fixing" in out assert python_file.read_text(encoding="utf8") == ( """ import a import b def function(): pass """ ) python_file.write(test_input) main.main([str(python_file), "--dont-float-to-top"]) _, error = capsys.readouterr() assert not error assert python_file.read_text(encoding="utf8") == test_input with pytest.raises(SystemExit): main.main([str(python_file), "--float-to-top", "--dont-float-to-top"]) def test_isort_with_stdin(capsys): # ensures that isort sorts stdin without any flags input_content = as_stream( """ import b import a """ ) main.main(["-"], stdin=input_content) out, error = capsys.readouterr() assert out == ( """ import a import b """ ) input_content_from = as_stream( """ import c import b from a import z, y, x """ ) main.main(["-"], stdin=input_content_from) out, error = capsys.readouterr() assert out == ( """ import b import c from a import x, y, z """ ) # ensures that isort correctly sorts stdin with --fas flag input_content = as_stream( """ import sys import pandas from z import abc from a import xyz """ ) main.main(["-", "--fas"], stdin=input_content) out, error = capsys.readouterr() assert out == ( """ from a import xyz from z import abc import pandas import sys """ ) # ensures that isort correctly sorts stdin with --fass flag input_content = as_stream( """ from a import Path, abc """ ) main.main(["-", "--fass"], stdin=input_content) out, error = capsys.readouterr() assert out == ( """ from a import abc, Path """ ) # ensures that isort correctly sorts stdin with --ff flag input_content = as_stream( """ import b from c import x from a import y """ ) main.main(["-", "--ff"], stdin=input_content) out, error = capsys.readouterr() assert out == ( """ from a import y from c import x import b """ ) # ensures that isort correctly sorts stdin with -fss flag input_content = as_stream( """ import b from a import a """ ) main.main(["-", "--fss"], stdin=input_content) out, error = capsys.readouterr() assert out == ( """ from a import a import b """ ) input_content = as_stream( """ import a from b import c """ ) main.main(["-", "--fss"], stdin=input_content) out, error = capsys.readouterr() assert out == ( """ import a from b import c """ ) # ensures that isort correctly sorts stdin with --ds flag input_content = as_stream( """ import sys import pandas import a """ ) main.main(["-", "--ds"], stdin=input_content) out, error = capsys.readouterr() assert out == ( """ import a import pandas import sys """ ) # ensures that isort correctly sorts stdin with --cs flag input_content = as_stream( """ from a import b from a import * """ ) main.main(["-", "--cs"], stdin=input_content) out, error = capsys.readouterr() assert out == ( """ from a import * """ ) # ensures that isort correctly sorts stdin with --ca flag input_content = as_stream( """ from a import x as X from a import y as Y """ ) main.main(["-", "--ca"], stdin=input_content) out, error = capsys.readouterr() assert out == ( """ from a import x as X, y as Y """ ) # ensures that isort works consistently with check and ws flags input_content = as_stream( """ import os import a import b """ ) main.main(["-", "--check-only", "--ws"], stdin=input_content) out, error = capsys.readouterr() assert not error # ensures that isort works consistently with check and diff flags input_content = as_stream( """ import b import a """ ) with pytest.raises(SystemExit): main.main(["-", "--check", "--diff"], stdin=input_content) out, error = capsys.readouterr() assert error assert "underlying stream is not seekable" not in error assert "underlying stream is not seekable" not in error # ensures that isort correctly sorts stdin with --ls flag input_content = as_stream( """ import abcdef import x """ ) main.main(["-", "--ls"], stdin=input_content) out, error = capsys.readouterr() assert out == ( """ import x import abcdef """ ) # ensures that isort correctly sorts stdin with --nis flag input_content = as_stream( """ from z import b, c, a """ ) main.main(["-", "--nis"], stdin=input_content) out, error = capsys.readouterr() assert out == ( """ from z import b, c, a """ ) # ensures that isort correctly sorts stdin with --sl flag input_content = as_stream( """ from z import b, c, a """ ) main.main(["-", "--sl"], stdin=input_content) out, error = capsys.readouterr() assert out == ( """ from z import a from z import b from z import c """ ) # ensures that isort correctly sorts stdin with --top flag input_content = as_stream( """ import os import sys """ ) main.main(["-", "--top", "sys"], stdin=input_content) out, error = capsys.readouterr() assert out == ( """ import sys import os """ ) # ensure that isort correctly sorts stdin with --os flag input_content = as_stream( """ import sys import os import z from a import b, e, c """ ) main.main(["-", "--os"], stdin=input_content) out, error = capsys.readouterr() assert out == ( """ import sys import os import z from a import b, e, c """ ) # ensures that isort warns with deprecated flags with stdin input_content = as_stream( """ import sys import os """ ) with pytest.warns(UserWarning): main.main(["-", "-ns"], stdin=input_content) out, error = capsys.readouterr() assert out == ( """ import os import sys """ ) input_content = as_stream( """ import sys import os """ ) with pytest.warns(UserWarning): main.main(["-", "-k"], stdin=input_content) out, error = capsys.readouterr() assert out == ( """ import os import sys """ ) # ensures that only-modified flag works with stdin input_content = as_stream( """ import a import b """ ) main.main(["-", "--verbose", "--only-modified"], stdin=input_content) out, error = capsys.readouterr() assert "else-type place_module for a returned THIRDPARTY" not in out assert "else-type place_module for b returned THIRDPARTY" not in out # ensures that combine-straight-imports flag works with stdin input_content = as_stream( """ import a import b """ ) main.main(["-", "--combine-straight-imports"], stdin=input_content) out, error = capsys.readouterr() assert out == ( """ import a, b """ ) def test_unsupported_encodings(tmpdir, capsys): tmp_file = tmpdir.join("file.py") # fmt: off tmp_file.write_text( ''' # [syntax-error]\ # -*- coding: IBO-8859-1 -*- """ check correct unknown encoding declaration """ __revision__ = 'יייי' ''', encoding="utf8" ) # fmt: on # should throw an error if only unsupported encoding provided with pytest.raises(SystemExit): main.main([str(tmp_file)]) out, error = capsys.readouterr() assert "No valid encodings." in error # should not throw an error if at least one valid encoding found normal_file = tmpdir.join("file1.py") normal_file.write("import os\nimport sys") main.main([str(tmp_file), str(normal_file), "--verbose"]) out, error = capsys.readouterr() def test_stream_skip_file(tmpdir, capsys): input_with_skip = """ # isort: skip_file import b import a """ stream_with_skip = as_stream(input_with_skip) main.main(["-"], stdin=stream_with_skip) out, error = capsys.readouterr() assert out == input_with_skip input_without_skip = input_with_skip.replace("isort: skip_file", "generic comment") stream_without_skip = as_stream(input_without_skip) main.main(["-"], stdin=stream_without_skip) out, error = capsys.readouterr() assert ( out == """ # generic comment import a import b """ ) atomic_input_without_skip = input_with_skip.replace("isort: skip_file", "generic comment") stream_without_skip = as_stream(atomic_input_without_skip) main.main(["-", "--atomic"], stdin=stream_without_skip) out, error = capsys.readouterr() assert ( out == """ # generic comment import a import b """ ) def test_only_modified_flag(tmpdir, capsys): # ensures there is no verbose output for correct files with only-modified flag file1 = tmpdir.join("file1.py") file1.write( """ import a import b """ ) file2 = tmpdir.join("file2.py") file2.write( """ import math import pandas as pd """ ) main.main([str(file1), str(file2), "--verbose", "--only-modified"]) out, error = capsys.readouterr() assert ( out == f""" _ _ (_) ___ ___ _ __| |_ | |/ _/ / _ \\/ '__ _/ | |\\__ \\/\\_\\/| | | |_ |_|\\___/\\___/\\_/ \\_/ isort your imports, so you don't have to. VERSION {__version__} """ ) assert not error # ensures that verbose output is only for modified file(s) with only-modified flag file3 = tmpdir.join("file3.py") file3.write( """ import sys import os """ ) main.main([str(file1), str(file2), str(file3), "--verbose", "--only-modified"]) out, error = capsys.readouterr() assert "else-type place_module for sys returned STDLIB" in out assert "else-type place_module for os returned STDLIB" in out assert "else-type place_module for math returned STDLIB" not in out assert "else-type place_module for pandas returned THIRDPARTY" not in out assert not error # ensures that the behaviour is consistent for check flag with only-modified flag main.main([str(file1), str(file2), "--check-only", "--verbose", "--only-modified"]) out, error = capsys.readouterr() assert ( out == f""" _ _ (_) ___ ___ _ __| |_ | |/ _/ / _ \\/ '__ _/ | |\\__ \\/\\_\\/| | | |_ |_|\\___/\\___/\\_/ \\_/ isort your imports, so you don't have to. VERSION {__version__} """ ) assert not error file4 = tmpdir.join("file4.py") file4.write( """ import sys import os """ ) with pytest.raises(SystemExit): main.main([str(file2), str(file4), "--check-only", "--verbose", "--only-modified"]) out, error = capsys.readouterr() assert "else-type place_module for sys returned STDLIB" in out assert "else-type place_module for os returned STDLIB" in out assert "else-type place_module for math returned STDLIB" not in out assert "else-type place_module for pandas returned THIRDPARTY" not in out def test_identify_imports_main(tmpdir, capsys): file_content = "import mod2\nimport mod2\n" "a = 1\n" "import mod1\n" some_file = tmpdir.join("some_file.py") some_file.write(file_content) file_imports = f"{some_file}:1 import mod2\n{some_file}:4 import mod1\n" file_imports_with_dupes = ( f"{some_file}:1 import mod2\n{some_file}:2 import mod2\n" f"{some_file}:4 import mod1\n" ) main.identify_imports_main([str(some_file), "--unique"]) out, error = capsys.readouterr() assert out.replace("\r\n", "\n") == file_imports assert not error main.identify_imports_main([str(some_file)]) out, error = capsys.readouterr() assert out.replace("\r\n", "\n") == file_imports_with_dupes assert not error main.identify_imports_main(["-", "--unique"], stdin=as_stream(file_content)) out, error = capsys.readouterr() assert out.replace("\r\n", "\n") == file_imports.replace(str(some_file), "") main.identify_imports_main(["-"], stdin=as_stream(file_content)) out, error = capsys.readouterr() assert out.replace("\r\n", "\n") == file_imports_with_dupes.replace(str(some_file), "") main.identify_imports_main([str(tmpdir)]) main.identify_imports_main(["-", "--packages"], stdin=as_stream(file_content)) out, error = capsys.readouterr() assert len(out.split("\n")) == 6 main.identify_imports_main(["-", "--modules"], stdin=as_stream(file_content)) out, error = capsys.readouterr() assert len(out.split("\n")) == 3 main.identify_imports_main(["-", "--attributes"], stdin=as_stream(file_content)) out, error = capsys.readouterr() assert len(out.split("\n")) == 3 def test_gitignore(capsys, tmp_path: pathlib.Path): import_content = """ import b import a """ def main_check(args): try: main.main(args) except SystemExit: pass return capsys.readouterr() subprocess.run(["git", "init", str(tmp_path)]) python_file = tmp_path / "has_imports.py" python_file.write_text(import_content) (tmp_path / "no_imports.py").write_text("...") out, error = main_check([str(python_file), "--skip-gitignore", "--filter-files", "--check"]) assert "has_imports.py" in error assert "no_imports.py" not in error (tmp_path / ".gitignore").write_text("has_imports.py") out, error = main_check([str(python_file), "--check"]) assert "has_imports.py" in error assert "no_imports.py" not in error out, error = main_check([str(python_file), "--skip-gitignore", "--filter-files", "--check"]) assert "Skipped" in out # Should work with nested directories (tmp_path / "nested_dir").mkdir() (tmp_path / ".gitignore").write_text("nested_dir/has_imports.py") subfolder_file = tmp_path / "nested_dir/has_imports.py" subfolder_file.write_text(import_content) out, error = main_check([str(tmp_path), "--skip-gitignore", "--filter-files", "--check"]) assert "has_imports.py" in error assert "nested_dir/has_imports.py" not in error # Should work with relative path currentdir = os.getcwd() os.chdir(tmp_path) out, error = main_check([".", "--skip-gitignore", "--filter-files", "--check"]) assert "has_imports.py" in error assert "nested_dir/has_imports.py" not in error (tmp_path / ".gitignore").write_text( """ nested_dir/has_imports.py has_imports.py """ ) out, error = main_check([".", "--skip-gitignore", "--filter-files", "--check"]) assert "Skipped" in out os.chdir(currentdir) # Should work with multiple git projects shutil.rmtree(tmp_path / ".git") (tmp_path / ".gitignore").unlink() # git_project0 # | has_imports_ignored.py ignored # | has_imports.py should check git_project0 = tmp_path / "git_project0" git_project0.mkdir() subprocess.run(["git", "init", str(git_project0)]) (git_project0 / ".gitignore").write_text("has_imports_ignored.py") (git_project0 / "has_imports_ignored.py").write_text(import_content) (git_project0 / "has_imports.py").write_text(import_content) # git_project1 # | has_imports.py should check # | nested_dir # | has_imports_ignored.py ignored # | has_imports.py should check # | nested_dir_ignored ignored # | has_imports.py ignored from folder git_project1 = tmp_path / "git_project1" git_project1.mkdir() subprocess.run(["git", "init", str(git_project1)]) (git_project1 / ".gitignore").write_text( """ nested_dir/has_imports_ignored.py nested_dir_ignored """ ) (git_project1 / "has_imports.py").write_text(import_content) nested_dir = git_project1 / "nested_dir" nested_dir.mkdir() (nested_dir / "has_imports.py").write_text(import_content) (nested_dir / "has_imports_ignored.py").write_text(import_content) nested_ignored_dir = git_project1 / "nested_dir_ignored" nested_ignored_dir.mkdir() (nested_ignored_dir / "has_imports.py").write_text(import_content) should_check = [ "/has_imports.py", "/nested_dir/has_imports.py", "/git_project0/has_imports.py", "/git_project1/has_imports.py", "/git_project1/nested_dir/has_imports.py", ] out, error = main_check([str(tmp_path), "--skip-gitignore", "--filter-files", "--check"]) if os.name == "nt": should_check = [sc.replace("/", "\\") for sc in should_check] assert all(f"{tmp_path}{file}" in error for file in should_check) out, error = main_check([str(tmp_path), "--skip-gitignore", "--filter-files"]) assert all(f"{tmp_path}{file}" in out for file in should_check) # Should work when git project contains symlinks if os.name != "nt": (git_project0 / "has_imports_ignored.py").write_text(import_content) (git_project0 / "has_imports.py").write_text(import_content) (tmp_path / "has_imports.py").write_text(import_content) (tmp_path / "nested_dir" / "has_imports.py").write_text(import_content) (git_project0 / "ignore_link.py").symlink_to(tmp_path / "has_imports.py") (git_project0 / "ignore_link").symlink_to(tmp_path / "nested_dir") gitignore = git_project0 / ".gitignore" gitignore.write_text(gitignore.read_text() + "ignore_link.py\nignore_link") out, error = main_check( [str(git_project0), "--skip-gitignore", "--filter-files", "--check"] ) should_check = ["/git_project0/has_imports.py"] assert all(f"{tmp_path}{file}" in error for file in should_check) out, error = main_check([str(git_project0), "--skip-gitignore", "--filter-files"]) assert all(f"{tmp_path}{file}" in out for file in should_check) def test_multiple_configs(capsys, tmpdir): # Ensure that --resolve-all-configs flag resolves multiple configs correctly # and sorts files corresponding to their nearest config setup_cfg = """ [isort] from_first=True """ pyproject_toml = """ [tool.isort] no_inline_sort = \"True\" """ isort_cfg = """ [settings] force_single_line=True """ broken_isort_cfg = """ [iaort_confg] force_single_line=True """ dir1 = tmpdir / "subdir1" dir2 = tmpdir / "subdir2" dir3 = tmpdir / "subdir3" dir4 = tmpdir / "subdir4" dir1.mkdir() dir2.mkdir() dir3.mkdir() dir4.mkdir() setup_cfg_file = dir1 / "setup.cfg" setup_cfg_file.write_text(setup_cfg, "utf-8") pyproject_toml_file = dir2 / "pyproject.toml" pyproject_toml_file.write_text(pyproject_toml, "utf-8") isort_cfg_file = dir3 / ".isort.cfg" isort_cfg_file.write_text(isort_cfg, "utf-8") broken_isort_cfg_file = dir4 / ".isort.cfg" broken_isort_cfg_file.write_text(broken_isort_cfg, "utf-8") import_section = """ from a import y, z, x import b """ file1 = dir1 / "file1.py" file1.write_text(import_section, "utf-8") file2 = dir2 / "file2.py" file2.write_text(import_section, "utf-8") file3 = dir3 / "file3.py" file3.write_text(import_section, "utf-8") file4 = dir4 / "file4.py" file4.write_text(import_section, "utf-8") file5 = tmpdir / "file5.py" file5.write_text(import_section, "utf-8") main.main([str(tmpdir), "--resolve-all-configs", "--cr", str(tmpdir), "--verbose"]) out, _ = capsys.readouterr() assert f"{setup_cfg_file} used for file {file1}" in out assert f"{pyproject_toml_file} used for file {file2}" in out assert f"{isort_cfg_file} used for file {file3}" in out assert f"default used for file {file4}" in out assert f"default used for file {file5}" in out assert ( file1.read() == """ from a import x, y, z import b """ ) assert ( file2.read() == """ import b from a import y, z, x """ ) assert ( file3.read() == """ import b from a import x from a import y from a import z """ ) assert ( file4.read() == """ import b from a import x, y, z """ ) assert ( file5.read() == """ import b from a import x, y, z """ ) # Ensure that --resolve-all-config flags works with --check file6 = dir1 / "file6.py" file6.write( """ import b from a import x, y, z """ ) with pytest.raises(SystemExit): main.main([str(tmpdir), "--resolve-all-configs", "--cr", str(tmpdir), "--check"]) _, err = capsys.readouterr() assert f"{file6} Imports are incorrectly sorted and/or formatted" in err def test_multiple_src_paths(tmpdir, capsys): """ Ensure that isort has consistent behavior with multiple source paths """ tests_module = tmpdir / "tests" app_module = tmpdir / "app" tests_module.mkdir() app_module.mkdir() pyproject_toml = tmpdir / "pyproject.toml" pyproject_toml.write_text( """ [tool.isort] profile = "black" src_paths = ["app", "tests"] auto_identify_namespace_packages = false """, "utf-8", ) file = tmpdir / "file.py" file.write_text( """ from app.something import something from tests.something import something_else """, "utf-8", ) for _ in range(10): # To ensure isort has consistent results in multiple runs main.main([str(tmpdir), "--verbose"]) out, _ = capsys.readouterr() assert ( file.read() == """ from app.something import something from tests.something import something_else """ ) assert "from-type place_module for tests.something returned FIRSTPARTY" in out isort-6.0.1/tests/unit/test_output.py0000644000000000000000000000110213615410400014662 0ustar00from hypothesis import given, reject from hypothesis import strategies as st import isort.comments @given( comments=st.one_of(st.none(), st.lists(st.text())), original_string=st.text(), removed=st.booleans(), comment_prefix=st.text(), ) def test_fuzz_add_to_line(comments, original_string, removed, comment_prefix): try: isort.comments.add_to_line( comments=comments, original_string=original_string, removed=removed, comment_prefix=comment_prefix, ) except ValueError: reject() isort-6.0.1/tests/unit/test_parse.py0000644000000000000000000000540713615410400014450 0ustar00import pytest from hypothesis import given from hypothesis import strategies as st from isort import parse from isort.settings import Config TEST_CONTENTS = """ import xyz import abc import (\\ # one one as \\ # two three) import \\ zebra as \\ # one not_bacon from x import (\\ # one one as \\ # two three) def function(): pass """ def test_file_contents(): ( in_lines, out_lines, import_index, _, _, _, _, _, change_count, original_line_count, _, _, _, _, ) = parse.file_contents(TEST_CONTENTS, config=Config(default_section="")) assert "\n".join(in_lines) == TEST_CONTENTS assert "import" not in "\n".join(out_lines) assert import_index == 1 assert change_count == -11 assert original_line_count == len(in_lines) # These tests were written by the `hypothesis.extra.ghostwriter` module # and is provided under the Creative Commons Zero public domain dedication. @given(contents=st.text()) def test_fuzz__infer_line_separator(contents): parse._infer_line_separator(contents=contents) @given(import_string=st.text()) def test_fuzz__strip_syntax(import_string): parse.strip_syntax(import_string=import_string) @given(line=st.text(), config=st.builds(Config)) def test_fuzz_import_type(line, config): parse.import_type(line=line, config=config) @given( line=st.text(), in_quote=st.text(), index=st.integers(), section_comments=st.lists(st.text()), needs_import=st.booleans(), ) def test_fuzz_skip_line(line, in_quote, index, section_comments, needs_import): parse.skip_line( line=line, in_quote=in_quote, index=index, section_comments=section_comments, needs_import=needs_import, ) @pytest.mark.parametrize( ("raw_line", "expected"), [ ("from . cimport a", "from . cimport a"), ("from.cimport a", "from . cimport a"), ("from..cimport a", "from .. cimport a"), ("from . import a", "from . import a"), ("from.import a", "from . import a"), ("from..import a", "from .. import a"), ("import *", "import *"), ("import*", "import *"), ("from . import a", "from . import a"), # noqa: PT014 ("from .import a", "from . import a"), ("from ..import a", "from .. import a"), ("from . cimport a", "from . cimport a"), # noqa: PT014 ("from .cimport a", "from . cimport a"), ("from ..cimport a", "from .. cimport a"), ("from\t.\timport a", "from . import a"), ], ) def test_normalize_line(raw_line, expected): line, returned_raw_line = parse.normalize_line(raw_line) assert line == expected assert returned_raw_line == raw_line isort-6.0.1/tests/unit/test_place.py0000644000000000000000000000521313615410400014415 0ustar00"""Tests for the isort import placement module""" from functools import partial from isort import place, sections from isort.settings import Config def test_module(src_path): place_tester = partial(place.module, config=Config(src_paths=[src_path])) assert place_tester("isort") == sections.FIRSTPARTY assert place_tester("os") == sections.STDLIB assert place_tester(".deprecated") == sections.LOCALFOLDER assert place_tester("__future__") == sections.FUTURE assert place_tester("hug") == sections.THIRDPARTY def test_extra_standard_library(src_path): place_tester = partial( place.module, config=Config(src_paths=[src_path], extra_standard_library=["hug"]) ) assert place_tester("os") == sections.STDLIB assert place_tester("hug") == sections.STDLIB def test_no_standard_library_placement(): assert place.module_with_reason( "pathlib", config=Config(sections=["THIRDPARTY"], default_section="THIRDPARTY") ) == ("THIRDPARTY", "Default option in Config or universal default.") assert place.module("pathlib") == "STDLIB" def test_namespace_package_placement(examples_path): namespace_examples = examples_path / "namespaces" implicit = namespace_examples / "implicit" pkg_resource = namespace_examples / "pkg_resource" pkgutil = namespace_examples / "pkgutil" for namespace_test in (implicit, pkg_resource, pkgutil): print(namespace_test) config = Config(settings_path=namespace_test) no_namespaces = Config(settings_path=namespace_test, auto_identify_namespace_packages=False) namespace_override = Config(settings_path=namespace_test, known_firstparty=["root.name"]) assert place.module("root.name", config=config) == "THIRDPARTY" assert place.module("root.nested", config=config) == "FIRSTPARTY" assert place.module("root.name", config=no_namespaces) == "FIRSTPARTY" assert place.module("root.name", config=namespace_override) == "FIRSTPARTY" no_namespace = namespace_examples / "none" almost_implicit = namespace_examples / "almost-implicit" weird_encoding = namespace_examples / "weird_encoding" for lacks_namespace in (no_namespace, almost_implicit, weird_encoding): config = Config(settings_path=lacks_namespace) manual_namespace = Config(settings_path=lacks_namespace, namespace_packages=["root"]) assert place.module("root.name", config=config) == "FIRSTPARTY" assert place.module("root.nested", config=config) == "FIRSTPARTY" assert place.module("root.name", config=manual_namespace) == "THIRDPARTY" assert place.module("root.nested", config=config) == "FIRSTPARTY" isort-6.0.1/tests/unit/test_pylama_isort.py0000644000000000000000000000143313615410400016034 0ustar00from isort.pylama_isort import Linter class TestLinter: instance = Linter() def test_allow(self): assert not self.instance.allow("test_case.pyc") assert not self.instance.allow("test_case.c") assert self.instance.allow("test_case.py") def test_run(self, tmpdir): correct = tmpdir.join("incorrect.py") correct.write("import a\nimport b\n") assert not self.instance.run(str(correct)) incorrect = tmpdir.join("incorrect.py") incorrect.write("import b\nimport a\n") assert self.instance.run(str(incorrect)) def test_skip(self, tmpdir): incorrect = tmpdir.join("incorrect.py") incorrect.write("# isort: skip_file\nimport b\nimport a\n") assert not self.instance.run(str(incorrect)) isort-6.0.1/tests/unit/test_regressions.py0000644000000000000000000012224313615410400015677 0ustar00"""A growing set of tests designed to ensure isort doesn't have regressions in new versions""" from io import StringIO import pytest import isort def test_isort_duplicating_comments_issue_1264(): """Ensure isort doesn't duplicate comments when force_sort_within_sections is set to `True` as was the case in issue #1264: https://github.com/pycqa/isort/issues/1264 """ assert ( isort.code( """ from homeassistant.util.logging import catch_log_exception # Loading the config flow... from . import config_flow """, force_sort_within_sections=True, ).count("# Loading the config flow...") == 1 ) def test_moving_comments_issue_726(): test_input = ( "from Blue import models as BlueModels\n" "# comment for PlaidModel\n" "from Plaid.models import PlaidModel\n" ) assert isort.code(test_input, force_sort_within_sections=True) == test_input test_input = ( "# comment for BlueModels\n" "from Blue import models as BlueModels\n" "# comment for PlaidModel\n" "# another comment for PlaidModel\n" "from Plaid.models import PlaidModel\n" ) assert isort.code(test_input, force_sort_within_sections=True) == test_input def test_blank_lined_removed_issue_1275(): """Ensure isort doesn't accidentally remove blank lines after doc strings and before imports. See: https://github.com/pycqa/isort/issues/1275 """ assert ( isort.code( '''""" My docstring """ from b import thing from a import other_thing ''' ) == '''""" My docstring """ from a import other_thing from b import thing ''' ) assert ( isort.code( '''""" My docstring """ from b import thing from a import other_thing ''', add_imports=["from b import thing"], ) == '''""" My docstring """ from a import other_thing from b import thing ''' ) def test_blank_lined_removed_issue_1283(): """Ensure isort doesn't accidentally remove blank lines after __version__ identifiers. See: https://github.com/pycqa/isort/issues/1283 """ test_input = """__version__ = "0.58.1" from starlette import status """ assert isort.code(test_input) == test_input def test_extra_blank_line_added_nested_imports_issue_1290(): """Ensure isort doesn't add unnecessary blank lines above nested imports. See: https://github.com/pycqa/isort/issues/1290 """ test_input = '''from typing import TYPE_CHECKING # Special imports from special import thing if TYPE_CHECKING: # Special imports from special import another_thing def func(): """Docstring""" # Special imports from special import something_else return ''' assert ( isort.code( test_input, import_heading_special="Special imports", known_special=["special"], sections=["FUTURE", "STDLIB", "THIRDPARTY", "SPECIAL", "FIRSTPARTY", "LOCALFOLDER"], ) == test_input ) def test_add_imports_shouldnt_make_isort_unusable_issue_1297(): """Test to ensure add imports doesn't cause any unexpected behaviour when combined with check See: https://github.com/pycqa/isort/issues/1297 """ assert isort.check_code( """from __future__ import unicode_literals from os import path """, add_imports={"from __future__ import unicode_literals"}, ) def test_no_extra_lines_for_imports_in_functions_issue_1277(): """Test to ensure isort doesn't introduce extra blank lines for imports within function. See: https://github.com/pycqa/isort/issues/1277 """ test_input = """ def main(): import time import sys """ expected_output = """ def main(): import sys import time """ assert isort.code(isort.code(isort.code(test_input))) == expected_output def test_no_extra_blank_lines_in_methods_issue_1293(): """Test to ensure isort isn't introducing extra lines in methods that contain imports See: https://github.com/pycqa/isort/issues/1293 """ test_input = """ class Something(object): def on_email_deleted(self, email): from hyperkitty.tasks import rebuild_thread_cache_new_email # update or cleanup thread # noqa: E303 (isort issue) if self.emails.count() == 0: ... """ assert isort.code(test_input) == test_input assert isort.code(test_input, lines_after_imports=2) == test_input def test_force_single_line_shouldnt_remove_preceding_comment_lines_issue_1296(): """Tests to ensure force_single_line setting doesn't result in lost comments. See: https://github.com/pycqa/isort/issues/1296 """ test_input = """ # A comment # A comment # Oh no, I'm gone from moo import foo """ # assert isort.code(test_input) == test_input assert isort.code(test_input, force_single_line=True) == test_input def test_ensure_new_line_before_comments_mixed_with_ensure_newline_before_comments_1295(): """Tests to ensure that the black profile can be used in conjunction with force_sort_within_sections. See: https://github.com/pycqa/isort/issues/1295 """ test_input = """ from openzwave.group import ZWaveGroup from openzwave.network import ZWaveNetwork # pylint: disable=import-error from openzwave.option import ZWaveOption """ assert isort.code(test_input, profile="black") == test_input assert isort.code(test_input, profile="black", force_sort_within_sections=True) == test_input def test_trailing_comma_doesnt_introduce_broken_code_with_comment_and_wrap_issue_1302(): """Tests to assert the combination of include_trailing_comma and a wrapped line doesnt break. See: https://github.com/pycqa/isort/issues/1302. """ assert ( isort.code( """ from somewhere import very_very_very_very_very_very_long_symbol # some comment """, line_length=50, include_trailing_comma=True, ) == """ from somewhere import \\ very_very_very_very_very_very_long_symbol # some comment """ ) def test_ensure_sre_parse_is_identified_as_stdlib_issue_1304(): """Ensure sre_parse is identified as STDLIB. See: https://github.com/pycqa/isort/issues/1304. """ assert ( isort.place_module("sre_parse") == isort.place_module("sre") == isort.settings.STDLIB # type: ignore # noqa ) def test_add_imports_shouldnt_move_lower_comments_issue_1300(): """Ensure add_imports doesn't move comments immediately below imports. See:: https://github.com/pycqa/isort/issues/1300. """ test_input = """from __future__ import unicode_literals from os import path # A comment for a constant ANSWER = 42 """ assert isort.code(test_input, add_imports=["from os import path"]) == test_input def test_windows_newline_issue_1277(): """Test to ensure windows new lines are correctly handled within indented scopes. See: https://github.com/pycqa/isort/issues/1277 """ assert ( isort.code("\ndef main():\r\n import time\r\n\n import sys\r\n") == "\ndef main():\r\n import sys\r\n import time\r\n" ) def test_windows_newline_issue_1278(): """Test to ensure windows new lines are correctly handled within indented scopes. See: https://github.com/pycqa/isort/issues/1278 """ assert isort.check_code( "\ntry:\r\n import datadog_agent\r\n\r\n " "from ..log import CheckLoggingAdapter, init_logging\r\n\r\n init_logging()\r\n" "except ImportError:\r\n pass\r\n" ) def test_check_never_passes_with_indented_headings_issue_1301(): """Test to ensure that test can pass even when there are indented headings. See: https://github.com/pycqa/isort/issues/1301 """ assert isort.check_code( """ try: # stdlib import logging from os import abc, path except ImportError: pass """, import_heading_stdlib="stdlib", ) def test_isort_shouldnt_fail_on_long_from_with_dot_issue_1190(): """Test to ensure that isort will correctly handle formatting a long from import that contains a dot. See: https://github.com/pycqa/isort/issues/1190 """ assert ( isort.code( """ from this_is_a_very_long_import_statement.that_will_occur_across_two_lines\\ .when_the_line_length.is_only_seventynine_chars import ( function1, function2, ) """, line_length=79, multi_line_output=3, ) == """ from this_is_a_very_long_import_statement.that_will_occur_across_two_lines""" """.when_the_line_length.is_only_seventynine_chars import ( function1, function2 ) """ ) def test_isort_shouldnt_add_extra_new_line_when_fass_and_n_issue_1315(): """Test to ensure isort doesnt add a second extra new line when combining --fss and -n options. See: https://github.com/pycqa/isort/issues/1315 """ assert isort.check_code( """import sys # Comment canary from . import foo """, ensure_newline_before_comments=True, # -n force_sort_within_sections=True, # -fss show_diff=True, # for better debugging in the case the test case fails. ) assert ( isort.code( """ from . import foo # Comment canary from .. import foo """, ensure_newline_before_comments=True, force_sort_within_sections=True, ) == """ from . import foo # Comment canary from .. import foo """ ) def test_isort_doesnt_rewrite_import_with_dot_to_from_import_issue_1280(): """Test to ensure isort doesn't rewrite imports in the from of import y.x into from y import x. This is because they are not technically fully equivalent to each other and can introduce broken behaviour. See: https://github.com/pycqa/isort/issues/1280 """ assert isort.check_code( """ import test.module import test.module as m from test import module from test import module as m """, show_diff=True, ) def test_isort_shouldnt_introduce_extra_lines_with_fass_issue_1322(): """Tests to ensure isort doesn't introduce extra lines when used with fass option. See: https://github.com/pycqa/isort/issues/1322 """ assert ( isort.code( """ import logging # Comment canary from foo import bar import quux """, force_sort_within_sections=True, ensure_newline_before_comments=True, ) == """ import logging # Comment canary from foo import bar import quux """ ) def test_comments_should_cause_wrapping_on_long_lines_black_mode_issue_1219(): """Tests to ensure if isort encounters a single import line which is made too long with a comment it is wrapped when using black profile. See: https://github.com/pycqa/isort/issues/1219 """ assert isort.check_code( """ from many_stop_words import ( get_stop_words as get_base_stopwords, # extended list of stop words, also for en ) """, show_diff=True, profile="black", ) def test_comment_blocks_should_stay_associated_without_extra_lines_issue_1156(): """Tests to ensure isort doesn't add an extra line when there are large import blocks or otherwise warp the intent. See: https://github.com/pycqa/isort/issues/1156 """ assert ( isort.code( """from top_level_ignored import config # isort:skip #################################### # COMMENT BLOCK SEPARATING THESE # #################################### from ast import excepthandler import logging """ ) == """from top_level_ignored import config # isort:skip import logging #################################### # COMMENT BLOCK SEPARATING THESE # #################################### from ast import excepthandler """ ) def test_comment_shouldnt_be_duplicated_with_fass_enabled_issue_1329(): """Tests to ensure isort doesn't duplicate comments when imports occur with comment on top, immediately after large comment blocks. See: https://github.com/pycqa/isort/pull/1329/files. """ assert isort.check_code( """''' Multi-line docstring ''' # Comment for A. import a # Comment for B - not A! import b """, force_sort_within_sections=True, show_diff=True, ) def test_wrap_mode_equal_to_line_length_with_indendet_imports_issue_1333(): assert isort.check_code( """ import a import b def function(): import a as b import c as d """, line_length=17, wrap_length=17, show_diff=True, ) def test_isort_skipped_nested_imports_issue_1339(): """Ensure `isort:skip are honored in nested imports. See: https://github.com/pycqa/isort/issues/1339. """ assert isort.check_code( """ def import_test(): from os ( # isort:skip import path ) """, show_diff=True, ) def test_windows_diff_too_large_misrepresentative_issue_1348(test_path): """Ensure isort handles windows files correctly when it come to producing a diff with --diff. See: https://github.com/pycqa/isort/issues/1348 """ diff_output = StringIO() isort.file(test_path / "example_crlf_file.py", show_diff=diff_output) diff_output.seek(0) assert diff_output.read().endswith( "-1,5 +1,5 @@\n+import a\r\n import b\r\n" "-import a\r\n \r\n \r\n def func():\r\n" ) def test_combine_as_does_not_lose_comments_issue_1321(): """Test to ensure isort doesn't lose comments when --combine-as is used. See: https://github.com/pycqa/isort/issues/1321 """ test_input = """ from foo import * # noqa from foo import bar as quux # other from foo import x as a # noqa import operator as op # op comment import datetime as dtime # dtime comment from datetime import date as d # dcomm from datetime import datetime as dt # dtcomm """ expected_output = """ import datetime as dtime # dtime comment import operator as op # op comment from datetime import date as d, datetime as dt # dcomm; dtcomm from foo import * # noqa from foo import bar as quux, x as a # other; noqa """ assert isort.code(test_input, combine_as_imports=True) == expected_output def test_combine_as_does_not_lose_comments_issue_1381(): """Test to ensure isort doesn't lose comments when --combine-as is used. See: https://github.com/pycqa/isort/issues/1381 """ test_input = """ from smtplib import SMTPConnectError, SMTPNotSupportedError # important comment """ assert "# important comment" in isort.code(test_input, combine_as_imports=True) test_input = """ from appsettings import AppSettings, ObjectSetting, StringSetting # type: ignore """ assert "# type: ignore" in isort.code(test_input, combine_as_imports=True) def test_incorrect_grouping_when_comments_issue_1396(): """Test to ensure isort groups import correct independent of the comments present. See: https://github.com/pycqa/isort/issues/1396 """ assert ( isort.code( """from django.shortcuts import render from apps.profiler.models import Project from django.contrib.auth.decorators import login_required from django.views.generic import ( # ListView, # DetailView, TemplateView, # CreateView, # View ) """, line_length=88, known_first_party=["apps"], known_django=["django"], sections=["FUTURE", "STDLIB", "DJANGO", "THIRDPARTY", "FIRSTPARTY", "LOCALFOLDER"], ) == """from django.contrib.auth.decorators import login_required from django.shortcuts import render from django.views.generic import \\ TemplateView # ListView,; DetailView,; CreateView,; View from apps.profiler.models import Project """ ) assert ( isort.code( """from django.contrib.auth.decorators import login_required from django.shortcuts import render from apps.profiler.models import Project from django.views.generic import ( # ListView,; DetailView,; CreateView,; View TemplateView, ) """, line_length=88, known_first_party=["apps"], known_django=["django"], sections=["FUTURE", "STDLIB", "DJANGO", "THIRDPARTY", "FIRSTPARTY", "LOCALFOLDER"], include_trailing_comma=True, multi_line_output=3, force_grid_wrap=0, use_parentheses=True, ensure_newline_before_comments=True, ) == """from django.contrib.auth.decorators import login_required from django.shortcuts import render from django.views.generic import ( # ListView,; DetailView,; CreateView,; View TemplateView, ) from apps.profiler.models import Project """ ) def test_reverse_relative_combined_with_force_sort_within_sections_issue_1395(): """Test to ensure reverse relative combines well with other common isort settings. See: https://github.com/pycqa/isort/issues/1395. """ assert isort.check_code( """from .fileA import a_var from ..fileB import b_var """, show_diff=True, reverse_relative=True, force_sort_within_sections=True, order_by_type=False, case_sensitive=False, multi_line_output=5, sections=["FUTURE", "STDLIB", "THIRDPARTY", "FIRSTPARTY", "APPLICATION", "LOCALFOLDER"], lines_after_imports=2, no_lines_before="LOCALFOLDER", ) def test_isort_should_be_able_to_add_independent_of_doc_string_placement_issue_1420(): """isort should be able to know when an import requested to be added is successfully added, independent of where the top doc string is located. See: https://github.com/PyCQA/isort/issues/1420 """ assert isort.check_code( '''"""module docstring""" import os ''', show_diff=True, add_imports=["os"], ) def test_comments_should_never_be_moved_between_imports_issue_1427(): """isort should never move comments to different import statement. See: https://github.com/PyCQA/isort/issues/1427 """ assert isort.check_code( """from package import CONSTANT from package import * # noqa """, force_single_line=True, show_diff=True, ) def test_isort_doesnt_misplace_comments_issue_1431(): """Test to ensure isort wont misplace comments. See: https://github.com/PyCQA/isort/issues/1431 """ input_text = """from com.my_lovely_company.my_lovely_team.my_lovely_project.my_lovely_component import ( MyLovelyCompanyTeamProjectComponent, # NOT DRY ) from com.my_lovely_company.my_lovely_team.my_lovely_project.my_lovely_component import ( MyLovelyCompanyTeamProjectComponent as component, # DRY ) """ assert isort.code(input_text, profile="black") == input_text def test_isort_doesnt_misplace_add_import_issue_1445(): """Test to ensure isort won't misplace an added import depending on docstring position See: https://github.com/PyCQA/isort/issues/1445 """ assert ( isort.code( '''#!/usr/bin/env python """module docstring""" ''', add_imports=["import os"], ) == '''#!/usr/bin/env python """module docstring""" import os ''' ) assert isort.check_code( '''#!/usr/bin/env python """module docstring""" import os ''', add_imports=["import os"], show_diff=True, ) def test_isort_doesnt_mangle_code_when_adding_imports_issue_1444(): """isort should NEVER mangle code. This particularly nasty and easy to reproduce bug, caused isort to produce invalid code just by adding a single import statement depending on comment placement. See: https://github.com/PyCQA/isort/issues/1444 """ assert ( isort.code( ''' """module docstring""" ''', add_imports=["import os"], ) == ''' """module docstring""" import os ''' ) def test_isort_float_to_top_with_sort_on_off_tests(): """Characterization test for current behaviour of float-to-top on isort: on/off sections. - imports in isort:off sections stay where they are - imports in isort:on sections float up, but to the top of the isort:on section (not the top of the file)""" assert ( isort.code( """ def foo(): pass import a # isort: off import stays_in_section x = 1 import stays_in_place # isort: on def bar(): pass import floats_to_top_of_section def baz(): pass """, float_to_top=True, ) == """import a def foo(): pass # isort: off import stays_in_section x = 1 import stays_in_place # isort: on import floats_to_top_of_section def bar(): pass def baz(): pass """ ) to_sort = """# isort: off def foo(): pass import stays_in_place import no_float_to_to_top import no_ordering def bar(): pass """ # No changes if isort is off assert isort.code(to_sort, float_to_top=True) == to_sort def test_isort_doesnt_float_to_top_correctly_when_imports_not_at_top_issue_1382(): """isort should float existing imports to the top, if they are currently below the top. See: https://github.com/PyCQA/isort/issues/1382 """ assert ( isort.code( """ def foo(): pass import a def bar(): pass """, float_to_top=True, ) == """import a def foo(): pass def bar(): pass """ ) assert ( isort.code( """ def foo(): pass import a def bar(): pass """, float_to_top=True, ) == """import a def foo(): pass def bar(): pass """ ) assert ( isort.code( '''"""My comment """ def foo(): pass import a def bar(): pass ''', float_to_top=True, ) == '''"""My comment """ import a def foo(): pass def bar(): pass ''' ) assert ( isort.code( ''' """My comment """ def foo(): pass import a def bar(): pass ''', float_to_top=True, ) == ''' """My comment """ import a def foo(): pass def bar(): pass ''' ) assert ( isort.code( '''#!/bin/bash """My comment """ def foo(): pass import a def bar(): pass ''', float_to_top=True, ) == '''#!/bin/bash """My comment """ import a def foo(): pass def bar(): pass ''' ) assert ( isort.code( '''#!/bin/bash """My comment """ def foo(): pass import a def bar(): pass ''', float_to_top=True, ) == '''#!/bin/bash """My comment """ import a def foo(): pass def bar(): pass ''' ) def test_empty_float_to_top_shouldnt_error_issue_1453(): """isort shouldn't error when float to top is set with a mostly empty file""" assert isort.check_code( """ """, show_diff=True, float_to_top=True, ) assert isort.check_code( """ """, show_diff=True, ) def test_import_sorting_shouldnt_be_endless_with_headers_issue_1454(): """isort should never enter an endless sorting loop. See: https://github.com/PyCQA/isort/issues/1454 """ assert isort.check_code( """ # standard library imports import sys try: # Comment about local lib # related third party imports from local_lib import stuff except ImportError as e: pass """, known_third_party=["local_lib"], import_heading_thirdparty="related third party imports", show_diff=True, ) def test_isort_should_leave_non_import_from_lines_alone_issue_1488(): """isort should never mangle non-import from statements. See: https://github.com/PyCQA/isort/issues/1488 """ raise_from_should_be_ignored = """ raise SomeException("Blah") \\ from exceptionsInfo.popitem()[1] """ assert isort.check_code(raise_from_should_be_ignored, show_diff=True) yield_from_should_be_ignored = """ def generator_function(): yield \\ from other_function()[1] """ assert isort.check_code(yield_from_should_be_ignored, show_diff=True) wont_ignore_comment_contiuation = """ # one # two def function(): # three \\ import b import a """ assert ( isort.code(wont_ignore_comment_contiuation) == """ # one # two def function(): # three \\ import a import b """ ) will_ignore_if_non_comment_continuation = """ # one # two def function(): raise \\ import b import a """ assert isort.check_code(will_ignore_if_non_comment_continuation, show_diff=True) yield_from_parens_should_be_ignored = """ def generator_function(): ( yield from other_function()[1] ) """ assert isort.check_code(yield_from_parens_should_be_ignored, show_diff=True) yield_from_lots_of_parens_and_space_should_be_ignored = """ def generator_function(): ( ( (((( ((((( (( ((( yield from other_function()[1] ))))))))))))) ))) """ assert isort.check_code(yield_from_lots_of_parens_and_space_should_be_ignored, show_diff=True) yield_from_should_be_ignored_when_following_import_statement = """ def generator_function(): import os yield \\ from other_function()[1] """ assert isort.check_code( yield_from_should_be_ignored_when_following_import_statement, show_diff=True ) yield_at_file_end_ignored = """ def generator_function(): ( ( (((( ((((( (( ((( yield """ assert isort.check_code(yield_at_file_end_ignored, show_diff=True) raise_at_file_end_ignored = """ def generator_function(): ( ( (((( ((((( (( ((( raise ( """ assert isort.check_code(raise_at_file_end_ignored, show_diff=True) raise_from_at_file_end_ignored = """ def generator_function(): ( ( (((( ((((( (( ((( raise \\ from \\ """ assert isort.check_code(raise_from_at_file_end_ignored, show_diff=True) def test_isort_float_to_top_correctly_identifies_single_line_comments_1499(): """Test to ensure isort correctly handles the case where float to top is used to push imports to the top and the top comment is a multiline type but only one line. See: https://github.com/PyCQA/isort/issues/1499 """ assert ( isort.code( '''#!/bin/bash """My comment""" def foo(): pass import a def bar(): pass ''', float_to_top=True, ) == ( '''#!/bin/bash """My comment""" import a def foo(): pass def bar(): pass ''' ) ) assert ( isort.code( """#!/bin/bash '''My comment''' def foo(): pass import a def bar(): pass """, float_to_top=True, ) == ( """#!/bin/bash '''My comment''' import a def foo(): pass def bar(): pass """ ) ) assert isort.check_code( """#!/bin/bash '''My comment''' import a x = 1 """, float_to_top=True, show_diff=True, ) def test_isort_shouldnt_mangle_from_multi_line_string_issue_1507(): """isort was seen mangling lines that happened to contain the word from after a yield happened to be in a file. Clearly this shouldn't happen. See: https://github.com/PyCQA/isort/issues/1507. """ assert isort.check_code( ''' def a(): yield f( """ select %s from (values %%s) as t(%s) """ ) def b(): return ( """ select name from foo """ % main_table ) def c(): query = ( """ select {keys} from (values %s) as t(id) """ ) def d(): query = f"""select t.id from {table} t {extra}""" ''', show_diff=True, ) def test_isort_should_keep_all_as_and_non_as_imports_issue_1523(): """isort should keep as and non-as imports of the same path that happen to exist within the same statement. See: https://github.com/PyCQA/isort/issues/1523. """ assert isort.check_code( """ from selenium.webdriver import Remote, Remote as Driver """, show_diff=True, combine_as_imports=True, ) def test_isort_shouldnt_introduce_syntax_error_issue_1539(): """isort should NEVER introduce syntax errors. In 5.5.4 some strings that contained a line starting with from could lead to no empty paren. See: https://github.com/PyCQA/isort/issues/1539. """ assert isort.check_code( '''"""Foobar from {}""".format( "bar", ) ''', show_diff=True, ) assert isort.check_code( '''"""Foobar import {}""".format( "bar", ) ''', show_diff=True, ) assert ( isort.code( '''"""Foobar from {}""" from a import b, a ''', ) == '''"""Foobar from {}""" from a import a, b ''' ) assert ( isort.code( '''"""Foobar from {}""" import b import a ''', ) == '''"""Foobar from {}""" import a import b ''' ) def test_isort_shouldnt_split_skip_issue_1548(): """Ensure isort doesn't add a spurious new line if isort: skip is combined with float to top. See: https://github.com/PyCQA/isort/issues/1548. """ assert isort.check_code( """from tools.dependency_pruning.prune_dependencies import ( # isort:skip prune_dependencies, ) """, show_diff=True, profile="black", float_to_top=True, ) assert isort.check_code( """from tools.dependency_pruning.prune_dependencies import ( # isort:skip prune_dependencies, ) import a import b """, show_diff=True, profile="black", float_to_top=True, ) assert isort.check_code( """from tools.dependency_pruning.prune_dependencies import # isort:skip import a import b """, show_diff=True, float_to_top=True, ) assert isort.check_code( """from tools.dependency_pruning.prune_dependencies import ( # isort:skip a ) import b """, show_diff=True, profile="black", float_to_top=True, ) assert isort.check_code( """from tools.dependency_pruning.prune_dependencies import ( # isort:skip ) """, show_diff=True, profile="black", float_to_top=True, ) assert isort.check_code( """from tools.dependency_pruning.prune_dependencies import ( # isort:skip )""", show_diff=True, profile="black", float_to_top=True, ) assert ( isort.code( """from tools.dependency_pruning.prune_dependencies import ( # isort:skip ) """, profile="black", float_to_top=True, add_imports=["import os"], ) == """from tools.dependency_pruning.prune_dependencies import ( # isort:skip ) import os """ ) assert ( isort.code( """from tools.dependency_pruning.prune_dependencies import ( # isort:skip )""", profile="black", float_to_top=True, add_imports=["import os"], ) == """from tools.dependency_pruning.prune_dependencies import ( # isort:skip ) import os """ ) def test_isort_shouldnt_split_skip_issue_1556(): assert isort.check_code( """ from tools.dependency_pruning.prune_dependencies import ( # isort:skip prune_dependencies, ) from tools.developer_pruning.prune_developers import ( # isort:skip prune_developers, ) """, show_diff=True, profile="black", float_to_top=True, ) assert isort.check_code( """ from tools.dependency_pruning.prune_dependencies import ( # isort:skip prune_dependencies, ) from tools.developer_pruning.prune_developers import x # isort:skip """, show_diff=True, profile="black", float_to_top=True, ) def test_isort_losing_imports_vertical_prefix_from_module_import_wrap_mode_issue_1542(): """Ensure isort doesnt lose imports when a comment is combined with an import and wrap mode VERTICAL_PREFIX_FROM_MODULE_IMPORT is used. See: https://github.com/PyCQA/isort/issues/1542. """ assert ( isort.code( """ from xxxxxxxxxxxxxxxx import AAAAAAAAAA, BBBBBBBBBB from xxxxxxxxxxxxxxxx import CCCCCCCCC, DDDDDDDDD # xxxxxxxxxxxxxxxxxx print(CCCCCCCCC) """, multi_line_output=9, ) == """ from xxxxxxxxxxxxxxxx import AAAAAAAAAA, BBBBBBBBBB # xxxxxxxxxxxxxxxxxx from xxxxxxxxxxxxxxxx import CCCCCCCCC, DDDDDDDDD print(CCCCCCCCC) """ ) assert isort.check_code( """ from xxxxxxxxxxxxxxxx import AAAAAAAAAA, BBBBBBBBBB from xxxxxxxxxxxxxxxx import CCCCCCCCC, DDDDDDDDD # xxxxxxxxxxxxxxxxxx isort: skip print(CCCCCCCCC) """, show_diff=True, multi_line_output=9, ) def test_isort_adding_second_comma_issue_1621(): """Ensure isort doesnt add a second comma when very long comment is present See: https://github.com/PyCQA/isort/issues/1621. """ assert isort.check_code( """from .test import ( TestTestTestTestTestTest2 as TestTestTestTestTestTest1, """ """# Some really long comment bla bla bla bla bla ) """, profile="black", show_diff=True, ) assert ( isort.code( """from .test import ( TestTestTestTestTestTest2 as TestTestTestTestTestTest1 """ """# Some really long comment bla bla bla bla bla ) """, profile="black", ) == """from .test import ( TestTestTestTestTestTest2 as TestTestTestTestTestTest1, """ """# Some really long comment bla bla bla bla bla ) """ ) def test_isort_shouldnt_duplicate_comments_issue_1631(): assert isort.check_code( """ import a # a comment import a as b # b comment """, show_diff=True, ) assert ( isort.code( """ import a # a comment import a as a # b comment """, remove_redundant_aliases=True, ) == """ import a # a comment; b comment """ ) def test_isort_shouldnt_add_extra_new_lines_with_import_heading_issue_1670(): snippet = """#!/usr/bin/python3 -ttu # Standard Library import argparse import datetime import attr import requests def foo() -> int: print("Hello world") return 0 def spam(): # Standard Library import collections import logging """ assert ( isort.code( snippet, import_heading_stdlib="Standard Library", ) == snippet ) def test_isort_shouldnt_add_extra_line_float_to_top_issue_1667(): assert isort.check_code( """ import sys sys.path.insert(1, 'path/containing/something_else/..') import something_else # isort:skip # Some constant SOME_CONSTANT = 4 """, show_diff=True, float_to_top=True, ) def test_isort_shouldnt_move_noqa_comment_issue_1594(): assert ( isort.code( """ from .test import TestTestTestTestTestTest1 # noqa: F401 from .test import TestTestTestTestTestTest2, TestTestTestTestTestTest3, """ """TestTestTestTestTestTest4, TestTestTestTestTestTest5 # noqa: F401 """, profile="black", ) == """ from .test import TestTestTestTestTestTest1 # noqa: F401 from .test import ( # noqa: F401 TestTestTestTestTestTest2, TestTestTestTestTestTest3, TestTestTestTestTestTest4, TestTestTestTestTestTest5, ) """ ) def test_isort_correctly_handles_unix_vs_linux_newlines_issue_1566(): import_statement = ( "from impacket.smb3structs import (\n" "SMB2_CREATE, SMB2_FLAGS_DFS_OPERATIONS, SMB2_IL_IMPERSONATION, " "SMB2_OPLOCK_LEVEL_NONE, SMB2Create," "\nSMB2Create_Response, SMB2Packet)\n" ) assert isort.code(import_statement, line_length=120) == isort.code( import_statement.replace("\n", "\r\n"), line_length=120 ).replace("\r\n", "\n") def test_isort_treats_src_paths_same_as_from_config_as_cli_issue_1711(tmpdir): assert isort.check_code( """ import mymodule import sqlalchemy """, show_diff=True, ) config_file = tmpdir.join(".isort.cfg") config_file.write( """ [settings] src_paths= api """ ) api_dir = tmpdir.mkdir("api") api_dir.join("mymodule.py").write("# comment") config = isort.settings.Config(str(config_file)) assert isort.check_code( """ import sqlalchemy import mymodule """, show_diff=True, config=config, ) def test_isort_should_never_quietly_remove_imports_in_hanging_line_mode_issue_1741(): assert ( isort.code( """ from src import abcd, qwerty, efg, xyz # some comment """, line_length=50, multi_line_output=2, ) == """ from src import abcd, efg, qwerty, xyz \\ # some comment """ ) assert ( isort.code( """ from src import abcd, qwerty, efg, xyz # some comment """, line_length=54, multi_line_output=2, ) == """ from src import abcd, efg, qwerty, xyz # some comment """ ) assert ( isort.code( """ from src import abcd, qwerty, efg, xyz # some comment """, line_length=53, multi_line_output=2, ) == """ from src import abcd, efg, qwerty, xyz \\ # some comment """ ) assert ( isort.code( """ from src import abcd, qwerty, efg, xyz # some comment """, line_length=30, multi_line_output=2, ) == """ from src import abcd, efg, \\ qwerty, xyz \\ # some comment """ ) @pytest.mark.parametrize("multi_line_output", range(12)) def test_isort_should_never_quietly_remove_imports_in_any_hangin_mode_issue_1741( multi_line_output: int, ): sorted_code = isort.code( """ from src import abcd, qwerty, efg, xyz # some comment """, line_length=30, multi_line_output=multi_line_output, ) assert "abcd" in sorted_code assert "qwerty" in sorted_code assert "efg" in sorted_code assert "xyz" in sorted_code def test_isort_should_keep_multi_noqa_with_star_issue_1744(): assert isort.check_code( """ from typing import * # noqa from typing import IO, BinaryIO, Union # noqa """, show_diff=True, ) assert isort.check_code( """ from typing import * # noqa 1 from typing import IO, BinaryIO, Union # noqa 2 """, show_diff=True, ) assert isort.check_code( """ from typing import * # noqa from typing import IO, BinaryIO, Union """, show_diff=True, ) assert isort.check_code( """ from typing import * from typing import IO, BinaryIO, Union # noqa """, show_diff=True, ) assert ( isort.code( """ from typing import * # hi from typing import IO, BinaryIO, Union # noqa """, combine_star=True, ) == """ from typing import * # noqa; hi """ ) assert ( isort.code( """ from typing import * # noqa from typing import IO, BinaryIO, Union # noqa """, combine_star=True, ) == """ from typing import * # noqa """ ) def test_isort_should_keep_multiple_noqa_comments_force_single_line_mode_issue_1721(): assert isort.check_code( """ from some_very_long_filename_to_import_from_that_causes_a_too_long_import_row import ( # noqa: E501 CONSTANT_1, ) from some_very_long_filename_to_import_from_that_causes_a_too_long_import_row import ( # noqa: E501 CONSTANT_2, ) """, show_diff=True, profile="black", force_single_line=True, ) def test_isort_should_only_add_imports_to_valid_location_issue_1769(): assert ( isort.code( '''v = """ """.split( "\n" ) ''', add_imports=["from __future__ import annotations"], ) == '''from __future__ import annotations v = """ """.split( "\n" ) ''' ) assert ( isort.code( '''v=""""""''', add_imports=["from __future__ import annotations"], ) == '''from __future__ import annotations v="""""" ''' ) def test_literal_sort_at_top_of_file_issue_1792(): assert ( isort.code( '''"""I'm a docstring! Look at me!""" # isort: unique-list __all__ = ["Foo", "Foo", "Bar"] from typing import final # arbitrary @final class Foo: ... @final class Bar: ... ''' ) == '''"""I'm a docstring! Look at me!""" # isort: unique-list __all__ = ['Bar', 'Foo'] from typing import final # arbitrary @final class Foo: ... @final class Bar: ... ''' ) def test_isort_should_produce_the_same_code_on_subsequent_runs_issue_1799(tmpdir): code = """import sys if sys.version_info[:2] >= (3, 8): # TODO: Import directly (no need for conditional) when `python_requires = >= 3.8` from importlib.metadata import PackageNotFoundError, version # pragma: no cover else: from importlib_metadata import PackageNotFoundError, version # pragma: no cover """ config_file = tmpdir.join(".isort.cfg") config_file.write( """[isort] profile=black src_paths=isort,test line_length=100 skip=.tox,.venv,build,dist,docs,tests extra_standard_library=pkg_resources,setuptools,typing known_test=pytest known_first_party=ibpt sections=FUTURE,STDLIB,TEST,THIRDPARTY,FIRSTPARTY,LOCALFOLDER import_heading_firstparty=internal import_heading_thirdparty=external """ ) settings = isort.settings.Config(str(config_file)) assert isort.code(code, config=settings) == isort.code( isort.code(code, config=settings), config=settings ) isort-6.0.1/tests/unit/test_settings.py0000644000000000000000000002316413615410400015176 0ustar00import os import sys from pathlib import Path import pytest from isort import exceptions, settings from isort.settings import Config from isort.wrap_modes import WrapModes class TestConfig: instance = Config() def test_init(self): assert Config() def test_init_unsupported_settings_fails_gracefully(self): with pytest.raises(exceptions.UnsupportedSettings): Config(apply=True) with pytest.raises(exceptions.UnsupportedSettings) as error: Config(apply=True) assert error.value.unsupported_settings == {"apply": {"value": True, "source": "runtime"}} def test_known_settings(self): assert Config(known_third_party=["one"]).known_third_party == frozenset({"one"}) assert Config(known_thirdparty=["two"]).known_third_party == frozenset({"two"}) assert Config( known_third_party=["one"], known_thirdparty=["two"] ).known_third_party == frozenset({"one"}) def test_invalid_settings_path(self): with pytest.raises(exceptions.InvalidSettingsPath): Config(settings_path="this_couldnt_possibly_actually_exists/could_it") def test_invalid_pyversion(self): with pytest.raises(ValueError, match="The python version 10 is not supported."): Config(py_version=10) def test_invalid_profile(self): with pytest.raises(exceptions.ProfileDoesNotExist): Config(profile="blackandwhitestylemixedwithpep8") def test_is_skipped(self): assert Config().is_skipped(Path("C:\\path\\isort.py")) assert Config(skip=["/path/isort.py"]).is_skipped(Path("C:\\path\\isort.py")) def test_is_supported_filetype(self): assert self.instance.is_supported_filetype("file.py") assert self.instance.is_supported_filetype("file.pyi") assert self.instance.is_supported_filetype("file.pyx") assert self.instance.is_supported_filetype("file.pxd") assert not self.instance.is_supported_filetype("file.pyc") assert not self.instance.is_supported_filetype("file.txt") assert not self.instance.is_supported_filetype("file.pex") def test_is_supported_filetype_ioerror(self, tmpdir): does_not_exist = tmpdir.join("fake.txt") assert not self.instance.is_supported_filetype(str(does_not_exist)) def test_is_supported_filetype_shebang(self, tmpdir): path = tmpdir.join("myscript") path.write("#!/usr/bin/env python\n") assert self.instance.is_supported_filetype(str(path)) def test_is_supported_filetype_editor_backup(self, tmpdir): path = tmpdir.join("myscript~") path.write("#!/usr/bin/env python\n") assert not self.instance.is_supported_filetype(str(path)) def test_is_supported_filetype_defaults(self, tmpdir): assert self.instance.is_supported_filetype(str(tmpdir.join("stub.pyi"))) assert self.instance.is_supported_filetype(str(tmpdir.join("source.py"))) assert self.instance.is_supported_filetype(str(tmpdir.join("source.pyx"))) def test_is_supported_filetype_configuration(self, tmpdir): config = Config(supported_extensions=("pyx",), blocked_extensions=("py",)) assert config.is_supported_filetype(str(tmpdir.join("stub.pyx"))) assert not config.is_supported_filetype(str(tmpdir.join("stub.py"))) @pytest.mark.skipif( sys.platform == "win32", reason="cannot create fifo file on Windows platform" ) def test_is_supported_filetype_fifo(self, tmpdir): fifo_file = os.path.join(tmpdir, "fifo_file") os.mkfifo(fifo_file) assert not self.instance.is_supported_filetype(fifo_file) def test_src_paths_are_combined_and_deduplicated(self): src_paths = ["src", "tests"] src_full_paths = (Path(os.getcwd()) / f for f in src_paths) assert sorted(Config(src_paths=src_paths * 2).src_paths) == sorted(src_full_paths) def test_src_paths_supports_glob_expansion(self, tmp_path): libs = tmp_path / "libs" libs.mkdir() requests = libs / "requests" requests.mkdir() beautifulpasta = libs / "beautifulpasta" beautifulpasta.mkdir() assert sorted(Config(directory=tmp_path, src_paths=["libs/*"]).src_paths) == sorted( (beautifulpasta, requests) ) def test_deprecated_multi_line_output(self): assert Config(multi_line_output=6).multi_line_output == WrapModes.VERTICAL_GRID_GROUPED # type: ignore # noqa def test_as_list(): assert settings._as_list([" one "]) == ["one"] # type: ignore assert settings._as_list("one,two") == ["one", "two"] def _write_simple_settings(tmp_file): tmp_file.write_text( """ [isort] force_grid_wrap=true """, "utf8", ) def test_find_config(tmpdir): tmp_config = tmpdir.join(".isort.cfg") # can't find config if it has no relevant section tmp_config.write_text( """ [section] force_grid_wrap=true """, "utf8", ) assert not settings._find_config(str(tmpdir))[1] # or if it is malformed tmp_config.write_text("""arstoyrsyan arienrsaeinrastyngpuywnlguyn354q^%$)(%_)@$""", "utf8") assert not settings._find_config(str(tmpdir))[1] # can when it has either a file format, or generic relevant section _write_simple_settings(tmp_config) assert settings._find_config(str(tmpdir))[1] def test_find_config_deep(tmpdir): # can't find config if it is further up than MAX_CONFIG_SEARCH_DEPTH dirs = [f"dir{i}" for i in range(settings.MAX_CONFIG_SEARCH_DEPTH + 1)] tmp_dirs = tmpdir.ensure(*dirs, dirs=True) tmp_config = tmpdir.join("dir0", ".isort.cfg") _write_simple_settings(tmp_config) assert not settings._find_config(str(tmp_dirs))[1] # but can find config if it is MAX_CONFIG_SEARCH_DEPTH up one_parent_up = os.path.split(str(tmp_dirs))[0] assert settings._find_config(one_parent_up)[1] def test_get_config_data(tmpdir): test_config = tmpdir.join("test_config.editorconfig") test_config.write_text( """ root = true [*.{js,py}] indent_style=tab indent_size=tab [*.py] force_grid_wrap=false comment_prefix="text" [*.{java}] indent_style = space """, "utf8", ) loaded_settings = settings._get_config_data( str(test_config), sections=settings.CONFIG_SECTIONS[".editorconfig"] ) assert loaded_settings assert loaded_settings["comment_prefix"] == "text" assert loaded_settings["force_grid_wrap"] == 0 assert loaded_settings["indent"] == "\t" assert str(tmpdir) in loaded_settings["source"] def test_editorconfig_without_sections(tmpdir): test_config = tmpdir.join("test_config.editorconfig") test_config.write_text("\nroot = true\n", "utf8") loaded_settings = settings._get_config_data(str(test_config), sections=("*.py",)) assert not loaded_settings def test_get_config_data_with_toml_and_utf8(tmpdir): test_config = tmpdir.join("pyproject.toml") # Exception: UnicodeDecodeError: 'gbk' codec can't decode byte 0x84 in position 57 test_config.write_text( """ [project] description = "基于FastAPI + Mysql的 TodoList" # Exception: UnicodeDecodeError name = "TodoList" version = "0.1.0" [tool.isort] multi_line_output = 3 """, "utf8", ) loaded_settings = settings._get_config_data( str(test_config), sections=settings.CONFIG_SECTIONS["pyproject.toml"] ) assert loaded_settings assert str(tmpdir) in loaded_settings["source"] def test_as_bool(): assert settings._as_bool("TrUe") is True assert settings._as_bool("true") is True assert settings._as_bool("t") is True assert settings._as_bool("FALSE") is False assert settings._as_bool("faLSE") is False assert settings._as_bool("f") is False with pytest.raises(ValueError, match="invalid truth value"): settings._as_bool("") with pytest.raises(ValueError, match="invalid truth value falsey"): settings._as_bool("falsey") with pytest.raises(ValueError, match="invalid truth value truthy"): settings._as_bool("truthy") def test_find_all_configs(tmpdir): setup_cfg = """ [isort] profile=django """ pyproject_toml = """ [tool.isort] profile = "hug" """ isort_cfg = """ [settings] profile=black """ pyproject_toml_broken = """ [tool.isorts] something = nothing """ dir1 = tmpdir / "subdir1" dir2 = tmpdir / "subdir2" dir3 = tmpdir / "subdir3" dir4 = tmpdir / "subdir4" dir1.mkdir() dir2.mkdir() dir3.mkdir() dir4.mkdir() setup_cfg_file = dir1 / "setup.cfg" setup_cfg_file.write_text(setup_cfg, "utf-8") pyproject_toml_file = dir2 / "pyproject.toml" pyproject_toml_file.write_text(pyproject_toml, "utf-8") isort_cfg_file = dir3 / ".isort.cfg" isort_cfg_file.write_text(isort_cfg, "utf-8") pyproject_toml_file_broken = dir4 / "pyproject.toml" pyproject_toml_file_broken.write_text(pyproject_toml_broken, "utf-8") config_trie = settings.find_all_configs(str(tmpdir)) config_info_1 = config_trie.search(str(dir1 / "test1.py")) assert config_info_1[0] == str(setup_cfg_file) assert config_info_1[0] == str(setup_cfg_file) assert config_info_1[1]["profile"] == "django" config_info_2 = config_trie.search(str(dir2 / "test2.py")) assert config_info_2[0] == str(pyproject_toml_file) assert config_info_2[0] == str(pyproject_toml_file) assert config_info_2[1]["profile"] == "hug" config_info_3 = config_trie.search(str(dir3 / "test3.py")) assert config_info_3[0] == str(isort_cfg_file) assert config_info_3[0] == str(isort_cfg_file) assert config_info_3[1]["profile"] == "black" config_info_4 = config_trie.search(str(tmpdir / "file4.py")) assert config_info_4[0] == "default" isort-6.0.1/tests/unit/test_setuptools_command.py0000644000000000000000000000163313615410400017252 0ustar00from isort import setuptools_commands def test_isort_command_smoke(src_dir): """A basic smoke test for the setuptools_commands command""" from setuptools.dist import Distribution command = setuptools_commands.ISortCommand(Distribution()) command.distribution.packages = ["isort"] command.distribution.package_dir = {"isort": src_dir} command.initialize_options() command.finalize_options() try: command.run() except SystemExit: pass command.distribution.package_dir = {"": "isort"} command.distribution.py_modules = ["one", "two"] command.initialize_options() command.finalize_options() command.run() command.distribution.packages = ["not_a_file"] command.distribution.package_dir = {"not_a_file": src_dir} command.initialize_options() command.finalize_options() try: command.run() except SystemExit: pass isort-6.0.1/tests/unit/test_ticketed_features.py0000644000000000000000000005633113615410400017032 0ustar00"""A growing set of tests designed to ensure when isort implements a feature described in a ticket it fully works as defined in the associated ticket. """ import warnings from functools import partial from io import StringIO import pytest import isort from isort import Config, exceptions def test_semicolon_ignored_for_dynamic_lines_after_import_issue_1178(): """Test to ensure even if a semicolon is in the decorator in the line following an import the correct line spacing determination will be made. See: https://github.com/pycqa/isort/issues/1178. """ assert isort.check_code( """ import pytest @pytest.mark.skip(';') def test_thing(): pass """, show_diff=True, ) def test_isort_automatically_removes_duplicate_aliases_issue_1193(): """Test to ensure isort can automatically remove duplicate aliases. See: https://github.com/pycqa/isort/issues/1281 """ assert isort.check_code("from urllib import parse as parse\n", show_diff=True) assert ( isort.code("from urllib import parse as parse", remove_redundant_aliases=True) == "from urllib import parse\n" ) assert isort.check_code("import os as os\n", show_diff=True) assert isort.code("import os as os", remove_redundant_aliases=True) == "import os\n" def test_isort_enables_floating_imports_to_top_of_module_issue_1228(): """Test to ensure isort will allow floating all non-indented imports to the top of a file. See: https://github.com/pycqa/isort/issues/1228. """ assert ( isort.code( """ import os def my_function_1(): pass import sys def my_function_2(): pass """, float_to_top=True, ) == """ import os import sys def my_function_1(): pass def my_function_2(): pass """ ) assert ( isort.code( """ import os def my_function_1(): pass # isort: split import sys def my_function_2(): pass """, float_to_top=True, ) == """ import os def my_function_1(): pass # isort: split import sys def my_function_2(): pass """ ) assert ( isort.code( """ import os def my_function_1(): pass # isort: off import b import a def y(): pass # isort: on import b def my_function_2(): pass import a """, float_to_top=True, ) == """ import os def my_function_1(): pass # isort: off import b import a def y(): pass # isort: on import a import b def my_function_2(): pass """ ) def test_isort_provides_official_api_for_diff_output_issue_1335(): """Test to ensure isort API for diff capturing allows capturing diff without sys.stdout. See: https://github.com/pycqa/isort/issues/1335. """ diff_output = StringIO() isort.code("import b\nimport a\n", show_diff=diff_output) diff_output.seek(0) assert "+import a" in diff_output.read() def test_isort_warns_when_known_sections_dont_match_issue_1331(): """Test to ensure that isort warns if there is a mismatch between sections and known_sections. See: https://github.com/pycqa/isort/issues/1331. """ assert ( isort.place_module( "bot_core", config=Config( known_robotlocomotion_upstream=["bot_core"], sections=["ROBOTLOCOMOTION_UPSTREAM", "THIRDPARTY"], ), ) == "ROBOTLOCOMOTION_UPSTREAM" ) with pytest.warns(UserWarning): assert ( isort.place_module( "bot_core", config=Config( known_robotlocomotion_upstream=["bot_core"], sections=["ROBOTLOOMOTION_UPSTREAM", "THIRDPARTY"], ), ) == "THIRDPARTY" ) with pytest.warns(UserWarning): assert ( isort.place_module( "bot_core", config=Config(known_robotlocomotion_upstream=["bot_core"]) ) == "THIRDPARTY" ) def test_isort_supports_append_only_imports_issue_727(): """Test to ensure isort provides a way to only add imports as an append. See: https://github.com/pycqa/isort/issues/727. """ assert isort.code("", add_imports=["from __future__ import absolute_imports"]) == "" assert ( isort.code("import os", add_imports=["from __future__ import absolute_imports"]) == """from __future__ import absolute_imports import os """ ) # issue 1838: don't append in middle of class assert isort.check_code( '''class C: """a """ # comment ''', append_only=True, add_imports=["from __future__ import annotations"], show_diff=True, ) def test_isort_supports_shared_profiles_issue_970(): """Test to ensure isort provides a way to use shared profiles. See: https://github.com/pycqa/isort/issues/970. """ assert isort.code("import a", profile="example") == "import a\n" # shared profile assert isort.code("import a", profile="black") == "import a\n" # bundled profile with pytest.raises(exceptions.ProfileDoesNotExist): assert isort.code("import a", profile="madeupfake") == "import a\n" # non-existent profile def test_treating_comments_as_code_issue_1357(): """Test to ensure isort provides a way to treat comments as code. See: https://github.com/pycqa/isort/issues/1357 """ assert ( isort.code( """# %% import numpy as np np.array([1,2,3]) # %% import pandas as pd pd.Series([1,2,3]) # %% # This is a comment on the second import import pandas as pd pd.Series([4,5,6])""", treat_comments_as_code=["# comment1", "# %%"], ) == """# %% import numpy as np np.array([1,2,3]) # %% import pandas as pd pd.Series([1,2,3]) # %% # This is a comment on the second import import pandas as pd pd.Series([4,5,6]) """ ) assert ( isort.code( """# %% import numpy as np np.array([1,2,3]) # %% import pandas as pd pd.Series([1,2,3]) # %% # This is a comment on the second import import pandas as pd pd.Series([4,5,6])""", treat_comments_as_code=["# comment1", "# %%"], float_to_top=True, ) == """# %% import numpy as np # This is a comment on the second import import pandas as pd np.array([1,2,3]) # %% pd.Series([1,2,3]) # %% pd.Series([4,5,6]) """ ) assert ( isort.code( """# %% import numpy as np np.array([1,2,3]) # %% import pandas as pd pd.Series([1,2,3]) # %% # This is a comment on the second import import pandas as pd pd.Series([4,5,6])""", treat_all_comments_as_code=True, ) == """# %% import numpy as np np.array([1,2,3]) # %% import pandas as pd pd.Series([1,2,3]) # %% # This is a comment on the second import import pandas as pd pd.Series([4,5,6]) """ ) assert ( isort.code( """import b # these are special imports that have to do with installing X plugin import c import a """, treat_all_comments_as_code=True, ) == """import b # these are special imports that have to do with installing X plugin import a import c """ ) def test_isort_allows_setting_import_types_issue_1181(): """Test to ensure isort provides a way to set the type of imports. See: https://github.com/pycqa/isort/issues/1181 """ assert isort.code("from x import AA, Big, variable") == "from x import AA, Big, variable\n" assert ( isort.code("from x import AA, Big, variable", constants=["variable"]) == "from x import AA, variable, Big\n" ) assert ( isort.code("from x import AA, Big, variable", variables=["AA"]) == "from x import Big, AA, variable\n" ) assert ( isort.code( "from x import AA, Big, variable", constants=["Big"], variables=["AA"], classes=["variable"], ) == "from x import Big, variable, AA\n" ) def test_isort_enables_deduping_section_headers_issue_953(): """isort should provide a way to only have identical import headings show up once. See: https://github.com/pycqa/isort/issues/953 """ isort_code = partial( isort.code, config=Config( import_heading_firstparty="Local imports.", import_heading_localfolder="Local imports.", dedup_headings=True, known_first_party=["isort"], ), ) assert ( isort_code("from . import something") == """# Local imports. from . import something """ ) assert ( isort_code( """from isort import y from . import something""" ) == """# Local imports. from isort import y from . import something """ ) assert isort_code("import os") == "import os\n" def test_isort_doesnt_remove_as_imports_when_combine_star_issue_1380(): """Test to ensure isort will not remove as imports along side other imports when requested to combine star imports together. See: https://github.com/PyCQA/isort/issues/1380 """ test_input = """ from a import a from a import * from a import b from a import b as y from a import c """ assert ( isort.code( test_input, combine_star=True, ) == isort.code(test_input, combine_star=True, force_single_line=True) == isort.code( test_input, combine_star=True, force_single_line=True, combine_as_imports=True, ) == """ from a import * from a import b as y """ ) def test_isort_support_custom_groups_above_stdlib_that_contain_stdlib_modules_issue_1407(): """Test to ensure it is possible to declare custom groups above standard library that include modules from the standard library. See: https://github.com/PyCQA/isort/issues/1407 """ assert isort.check_code( """ from __future__ import annotations from typing import * from pathlib import Path """, known_typing=["typing"], sections=["FUTURE", "TYPING", "STDLIB", "THIRDPARTY", "FIRSTPARTY", "LOCALFOLDER"], no_lines_before=["TYPING"], show_diff=True, ) def test_isort_intelligently_places_noqa_comments_issue_1456(): assert isort.check_code( """ from my.horribly.long.import.line.that.just.keeps.on.going.and.going.and.going import ( # noqa my_symbol, ) """, force_single_line=True, show_diff=True, multi_line_output=3, include_trailing_comma=True, force_grid_wrap=0, use_parentheses=True, line_length=79, ) assert isort.check_code( """ from my.horribly.long.import.line.that.just.keeps.on.going.and.going.and.going import ( my_symbol, ) """, force_single_line=True, show_diff=True, multi_line_output=3, include_trailing_comma=True, force_grid_wrap=0, use_parentheses=True, line_length=79, ) assert isort.check_code( """ from my.horribly.long.import.line.that.just.keeps.on.going.and.going.and.going import ( # noqa my_symbol ) """, force_single_line=True, use_parentheses=True, multi_line_output=3, line_length=79, show_diff=True, ) assert isort.check_code( """ from my.horribly.long.import.line.that.just.keeps.on.going.and.going.and.going import ( my_symbol ) """, force_single_line=True, use_parentheses=True, multi_line_output=3, line_length=79, show_diff=True, ) # see: https://github.com/PyCQA/isort/issues/1415 assert isort.check_code( "from dials.test.algorithms.spot_prediction." "test_scan_static_reflection_predictor import ( # noqa: F401\n" " data as static_test,\n)\n", profile="black", show_diff=True, ) def test_isort_respects_quiet_from_sort_file_api_see_1461(capsys, tmpdir): """Test to ensure isort respects the quiet API parameter when passed in via the API. See: https://github.com/PyCQA/isort/issues/1461. """ settings_file = tmpdir.join(".isort.cfg") custom_settings_file = tmpdir.join(".custom.isort.cfg") tmp_file = tmpdir.join("file.py") tmp_file.write("import b\nimport a\n") isort.file(tmp_file) out, error = capsys.readouterr() assert not error assert "Fixing" in out # When passed in directly as a setting override tmp_file.write("import b\nimport a\n") isort.file(tmp_file, quiet=True) out, error = capsys.readouterr() assert not error assert not out # Present in an automatically loaded configuration file settings_file.write( """ [isort] quiet = true """ ) tmp_file.write("import b\nimport a\n") isort.file(tmp_file) out, error = capsys.readouterr() assert not error assert not out # In a custom configuration file settings_file.write( """ [isort] quiet = false """ ) custom_settings_file.write( """ [isort] quiet = true """ ) tmp_file.write("import b\nimport a\n") isort.file(tmp_file, settings_file=str(custom_settings_file)) out, error = capsys.readouterr() assert not error assert not out # Reused configuration object custom_config = Config(settings_file=str(custom_settings_file)) isort.file(tmp_file, config=custom_config) out, error = capsys.readouterr() assert not error assert not out def test_isort_should_warn_on_empty_custom_config_issue_1433(tmpdir): """Feedback should be provided when a user provides a custom settings file that has no discoverable configuration. See: https://github.com/PyCQA/isort/issues/1433 """ settings_file = tmpdir.join(".custom.cfg") settings_file.write( """ [settings] quiet = true """ ) with pytest.warns(UserWarning): assert not Config(settings_file=str(settings_file)).quiet settings_file.write( """ [isort] quiet = true """ ) with warnings.catch_warnings(): warnings.simplefilter("error") assert Config(settings_file=str(settings_file)).quiet def test_float_to_top_should_respect_existing_newlines_between_imports_issue_1502(): """When a file has an existing top of file import block before code but after comments isort's float to top feature should respect the existing spacing between the top file comment and the import statements. See: https://github.com/PyCQA/isort/issues/1502 """ assert isort.check_code( """#!/bin/bash '''My comment''' import a x = 1 """, float_to_top=True, show_diff=True, ) assert isort.check_code( """#!/bin/bash '''My comment''' import a x = 1 """, float_to_top=True, show_diff=True, ) assert ( isort.code( """#!/bin/bash '''My comment''' import a x = 1 """, float_to_top=True, add_imports=["import b"], ) == """#!/bin/bash '''My comment''' import a import b x = 1 """ ) assert ( isort.code( """#!/bin/bash '''My comment''' def my_function(): pass import a """, float_to_top=True, ) == """#!/bin/bash '''My comment''' import a def my_function(): pass """ ) assert ( isort.code( """#!/bin/bash '''My comment''' def my_function(): pass """, add_imports=["import os"], float_to_top=True, ) == """#!/bin/bash '''My comment''' import os def my_function(): pass """ ) def test_api_to_allow_custom_diff_and_output_stream_1583(capsys, tmpdir): """isort should provide a way from the Python API to process an existing file and output to a stream the new version of that file, as well as a diff to a different stream. See: https://github.com/PyCQA/isort/issues/1583 """ tmp_file = tmpdir.join("file.py") tmp_file.write("import b\nimport a\n") isort_diff = StringIO() isort_output = StringIO() isort.file(tmp_file, show_diff=isort_diff, output=isort_output) _, error = capsys.readouterr() assert not error isort_diff.seek(0) isort_diff_content = isort_diff.read() assert "+import a" in isort_diff_content assert " import b" in isort_diff_content assert "-import a" in isort_diff_content isort_output.seek(0) assert isort_output.read().splitlines() == ["import a", "import b"] # should still work with no diff produced tmp_file2 = tmpdir.join("file2.py") tmp_file2.write("import a\nimport b\n") isort_diff2 = StringIO() isort_output2 = StringIO() isort.file(tmp_file2, show_diff=isort_diff2, output=isort_output2) _, error = capsys.readouterr() assert not error isort_diff2.seek(0) assert not isort_diff2.read() def test_autofix_mixed_indent_imports_1575(): """isort should automatically fix import statements that are sent in with incorrect mixed indentation. See: https://github.com/PyCQA/isort/issues/1575 """ assert ( isort.code( """ import os import os """ ) == """ import os """ ) assert ( isort.code( """ def one(): import os import os """ ) == """ def one(): import os import os """ ) assert ( isort.code( """ import os import os import os import os import os """ ) == """ import os """ ) def test_indented_import_headings_issue_1604(): """Test to ensure it is possible to toggle import headings on indented import sections See: https://github.com/PyCQA/isort/issues/1604 """ assert ( isort.code( """ import numpy as np def function(): import numpy as np """, import_heading_thirdparty="External imports", ) == """ # External imports import numpy as np def function(): # External imports import numpy as np """ ) assert ( isort.code( """ import numpy as np def function(): import numpy as np """, import_heading_thirdparty="External imports", indented_import_headings=False, ) == """ # External imports import numpy as np def function(): import numpy as np """ ) def test_isort_auto_detects_and_ignores_invalid_from_imports_issue_1688(): """isort should automatically detect and ignore incorrectly written from import statements see: https://github.com/PyCQA/isort/issues/1688 """ assert ( isort.code( """ from package1 import alright from package2 imprt and_its_gone from package3 import also_ok """ ) == """ from package1 import alright from package2 imprt and_its_gone from package3 import also_ok """ ) def test_isort_allows_reversing_sort_order_issue_1645(): """isort allows reversing the sort order for those who prefer Z or longer imports first. see: https://github.com/PyCQA/isort/issues/1688 """ assert ( isort.code( """ from xxx import ( g, hi, def, abcd, ) """, profile="black", reverse_sort=True, length_sort=True, line_length=20, ) == """ from xxx import ( abcd, def, hi, g, ) """ ) def test_isort_can_push_star_imports_above_others_issue_1504(): """isort should provide a way to push star imports above other imports to avoid explicit imports from being overwritten. see: https://github.com/PyCQA/isort/issues/1504 """ assert ( ( isort.code( """ from ._bar import Any, All, Not from ._foo import a, * """, star_first=True, ) ) == """ from ._foo import * from ._foo import a from ._bar import All, Any, Not """ ) def test_isort_can_combine_reverse_sort_with_force_sort_within_sections_issue_1726(): """isort should support reversing import order even with force sort within sections turned on. See: https://github.com/PyCQA/isort/issues/1726 """ assert ( isort.code( """ import blaaa from bl4aaaaaaaaaaaaaaaa import r import blaaaaaaaaaaaa import bla import blaaaaaaa from bl1aaaaaaaaaaaaaa import this_is_1 from bl2aaaaaaa import THIIIIIIIIIIIISS_is_2 from bl3aaaaaa import less """, length_sort=True, reverse_sort=True, force_sort_within_sections=True, ) == """ from bl2aaaaaaa import THIIIIIIIIIIIISS_is_2 from bl1aaaaaaaaaaaaaa import this_is_1 from bl4aaaaaaaaaaaaaaaa import r from bl3aaaaaa import less import blaaaaaaaaaaaa import blaaaaaaa import blaaa import bla """ ) def test_isort_can_turn_off_import_adds_with_action_comment_issue_1737(): assert ( isort.code( """ import os """, add_imports=[ "from __future__ import absolute_imports", "from __future__ import annotations", ], ) == """ from __future__ import absolute_imports, annotations import os """ ) assert isort.check_code( """ # isort: dont-add-imports import os """, show_diff=True, add_imports=[ "from __future__ import absolute_imports", "from __future__ import annotations", ], ) assert ( isort.code( """ # isort: dont-add-import: from __future__ import annotations import os """, add_imports=[ "from __future__ import absolute_imports", "from __future__ import annotations", ], ) == """ # isort: dont-add-import: from __future__ import annotations from __future__ import absolute_imports import os """ ) def test_sort_configurable_sort_issue_1732() -> None: """Test support for pluggable isort sort functions.""" test_input = ( "from bob2.apples2 import aardvark as aardvark2\n" "from bob.apples import aardvark \n" "import module9\n" "import module10\n" "import module200\n" ) assert isort.code(test_input, sort_order="native") == ( "import module10\n" "import module200\n" "import module9\n" "from bob.apples import aardvark\n" "from bob2.apples2 import aardvark as aardvark2\n" ) assert ( isort.code(test_input, sort_order="natural") == isort.code(test_input) == ( "import module9\n" "import module10\n" "import module200\n" "from bob2.apples2 import aardvark as aardvark2\n" "from bob.apples import aardvark\n" ) ) assert ( isort.code(test_input, sort_order="natural_plus") == isort.code(test_input) == ( "import module9\n" "import module10\n" "import module200\n" "from bob2.apples2 import aardvark as aardvark2\n" "from bob.apples import aardvark\n" ) ) with pytest.raises(exceptions.SortingFunctionDoesNotExist): isort.code(test_input, sort_order="round") def test_cython_pure_python_imports_2062(): """Test to ensure an import form a cython.cimports remains import, not cimport. See: https://github.com/pycqa/isort/issues/2062. """ assert isort.check_code( """ import cython from cython.cimports.libc import math def use_libc_math(): return math.ceil(5.5) """, show_diff=True, ) isort-6.0.1/tests/unit/test_utils.py0000644000000000000000000000304213615410400014467 0ustar00from isort.utils import Trie def test_trie(): trie_root = Trie("default", {"line_length": 70}) trie_root.insert("/temp/config1/.isort.cfg", {"line_length": 71}) trie_root.insert("/temp/config2/setup.cfg", {"line_length": 72}) trie_root.insert("/temp/config3/pyproject.toml", {"line_length": 73}) # Ensure that appropriate configs are resolved for files in different directories config1 = trie_root.search("/temp/config1/subdir/file1.py") assert config1[0] == "/temp/config1/.isort.cfg" assert config1[1] == {"line_length": 71} config1_2 = trie_root.search("/temp/config1/file1_2.py") assert config1_2[0] == "/temp/config1/.isort.cfg" assert config1_2[1] == {"line_length": 71} config2 = trie_root.search("/temp/config2/subdir/subsubdir/file2.py") assert config2[0] == "/temp/config2/setup.cfg" assert config2[1] == {"line_length": 72} config2_2 = trie_root.search("/temp/config2/subdir/file2_2.py") assert config2_2[0] == "/temp/config2/setup.cfg" assert config2_2[1] == {"line_length": 72} config3 = trie_root.search("/temp/config3/subdir/subsubdir/subsubsubdir/file3.py") assert config3[0] == "/temp/config3/pyproject.toml" assert config3[1] == {"line_length": 73} config3_2 = trie_root.search("/temp/config3/file3.py") assert config3_2[0] == "/temp/config3/pyproject.toml" assert config3_2[1] == {"line_length": 73} config_outside = trie_root.search("/temp/file.py") assert config_outside[0] == "default" assert config_outside[1] == {"line_length": 70} isort-6.0.1/tests/unit/test_wrap.py0000644000000000000000000000315413615410400014304 0ustar00import pytest from isort import wrap from isort.settings import Config from isort.wrap_modes import WrapModes def test_import_statement(): assert wrap.import_statement("", [], []) == "" assert ( wrap.import_statement("from x import ", ["y"], [], config=Config(balanced_wrapping=True)) == "from x import (y)" ) assert ( wrap.import_statement("from long_import ", ["verylong"] * 10, []) == """from long_import (verylong, verylong, verylong, verylong, verylong, verylong, verylong, verylong, verylong, verylong)""" ) assert wrap.import_statement("from x import ", ["y", "z"], [], explode=True) == ( "from x import (\n y,\n z,\n)" ) @pytest.mark.parametrize( ("multi_line_output", "expected"), [ ( WrapModes.VERTICAL_HANGING_INDENT, # type: ignore """from a import ( b as c # comment that is long enough that this import doesn't fit in one line (parens) )""", ), ( WrapModes.VERTICAL, # type: ignore """from a import ( b as c) # comment that is long enough that this import doesn't fit in one line (parens)""", ), ], ) def test_line__comment_with_brackets__expects_unchanged_comment(multi_line_output, expected): content = ( "from a import b as c " "# comment that is long enough that this import doesn't fit in one line (parens)" ) config = Config( multi_line_output=multi_line_output, use_parentheses=True, ) assert wrap.line(content=content, line_separator="\n", config=config) == expected isort-6.0.1/tests/unit/test_wrap_modes.py0000644000000000000000000004036513615410400015500 0ustar00import pytest from hypothesis import given, reject from hypothesis import strategies as st import isort from isort import wrap_modes def test_wrap_mode_interface(): assert ( wrap_modes._wrap_mode_interface("statement", [], "", "", 80, [], "", "", True, True) == "" ) def test_auto_saved(): """hypothesis_auto tests cases that have been saved to ensure they run each test cycle""" assert ( wrap_modes.noqa( **{ "comment_prefix": "-\U000bf82c\x0c\U0004608f\x10%", "comments": [], "imports": [], "include_trailing_comma": False, "indent": "0\x19", "line_length": -19659, "line_separator": "\x15\x0b\U00086494\x1d\U000e00a2\U000ee216\U0006708a\x03\x1f", "remove_comments": False, "statement": "\U00092452", "white_space": "\U000a7322\U000c20e3-\U0010eae4\x07\x14\U0007d486", } ) == "\U00092452-\U000bf82c\x0c\U0004608f\x10% NOQA" ) assert ( wrap_modes.noqa( **{ "comment_prefix": '\x12\x07\U0009e994🁣"\U000ae787\x0e', "comments": ["\x00\U0001ae99\U0005c3e7\U0004d08e", "\x1e", "", ""], "imports": ["*"], "include_trailing_comma": True, "indent": "", "line_length": 31492, "line_separator": "\U00071610\U0005bfbc", "remove_comments": False, "statement": "", "white_space": "\x08\x01ⷓ\x16%\U0006cd8c", } ) == '*\x12\x07\U0009e994🁣"\U000ae787\x0e \x00\U0001ae99\U0005c3e7\U0004d08e \x1e ' ) assert ( wrap_modes.noqa( **{ "comment_prefix": " #", "comments": ["NOQA", "THERE"], "imports": [], "include_trailing_comma": False, "indent": "0\x19", "line_length": -19659, "line_separator": "\n", "remove_comments": False, "statement": "hi", "white_space": " ", } ) == "hi # NOQA THERE" ) def test_backslash_grid(): """Tests the backslash_grid grid wrap mode, ensuring it matches formatting expectations. See: https://github.com/PyCQA/isort/issues/1434 """ assert ( isort.code( """ from kopf.engines import loggers, posting from kopf.reactor import causation, daemons, effects, handling, lifecycles, registries from kopf.storage import finalizers, states from kopf.structs import (bodies, configuration, containers, diffs, handlers as handlers_, patches, resources) """, multi_line_output=11, line_length=88, combine_as_imports=True, ) == """ from kopf.engines import loggers, posting from kopf.reactor import causation, daemons, effects, handling, lifecycles, registries from kopf.storage import finalizers, states from kopf.structs import bodies, configuration, containers, diffs, \\ handlers as handlers_, patches, resources """ ) @pytest.mark.parametrize("include_trailing_comma", [False, True]) @pytest.mark.parametrize("line_length", [18, 19]) @pytest.mark.parametrize("multi_line_output", [4, 5]) def test_vertical_grid_size_near_line_length( multi_line_output: int, line_length: int, include_trailing_comma: bool, ): separator = " " # Cases where the input should be wrapped: if ( # Mode 4 always adds a closing ")", making the imports line 19 chars, # if include_trailing_comma is True that becomes 20 chars. (multi_line_output == 4 and line_length < 19 + int(include_trailing_comma)) # Modes 5 and 6 only add a comma, if include_trailing_comma is True, # so their lines are 18 or 19 chars long. or (multi_line_output != 4 and line_length < 18 + int(include_trailing_comma)) ): separator = "\n " test_input = f"from foo import (\n aaaa, bbb,{separator}ccc" if include_trailing_comma: test_input += "," if multi_line_output != 4: test_input += "\n" test_input += ")\n" assert ( isort.code( test_input, multi_line_output=multi_line_output, line_length=line_length, include_trailing_comma=include_trailing_comma, ) == test_input ) # This test code was written by the `hypothesis.extra.ghostwriter` module # and is provided under the Creative Commons Zero public domain dedication. @given( statement=st.text(), imports=st.lists(st.text()), white_space=st.text(), indent=st.text(), line_length=st.integers(), comments=st.lists(st.text()), line_separator=st.text(), comment_prefix=st.text(), include_trailing_comma=st.booleans(), remove_comments=st.booleans(), ) def test_fuzz_backslash_grid( statement, imports, white_space, indent, line_length, comments, line_separator, comment_prefix, include_trailing_comma, remove_comments, ): try: isort.wrap_modes.backslash_grid( statement=statement, imports=imports, white_space=white_space, indent=indent, line_length=line_length, comments=comments, line_separator=line_separator, comment_prefix=comment_prefix, include_trailing_comma=include_trailing_comma, remove_comments=remove_comments, ) except ValueError: reject() @given( statement=st.text(), imports=st.lists(st.text()), white_space=st.text(), indent=st.text(), line_length=st.integers(), comments=st.lists(st.text()), line_separator=st.text(), comment_prefix=st.text(), include_trailing_comma=st.booleans(), remove_comments=st.booleans(), ) def test_fuzz_grid( statement, imports, white_space, indent, line_length, comments, line_separator, comment_prefix, include_trailing_comma, remove_comments, ): try: isort.wrap_modes.grid( statement=statement, imports=imports, white_space=white_space, indent=indent, line_length=line_length, comments=comments, line_separator=line_separator, comment_prefix=comment_prefix, include_trailing_comma=include_trailing_comma, remove_comments=remove_comments, ) except ValueError: reject() @given( statement=st.text(), imports=st.lists(st.text()), white_space=st.text(), indent=st.text(), line_length=st.integers(), comments=st.lists(st.text()), line_separator=st.text(), comment_prefix=st.text(), include_trailing_comma=st.booleans(), remove_comments=st.booleans(), ) def test_fuzz_hanging_indent( statement, imports, white_space, indent, line_length, comments, line_separator, comment_prefix, include_trailing_comma, remove_comments, ): try: isort.wrap_modes.hanging_indent( statement=statement, imports=imports, white_space=white_space, indent=indent, line_length=line_length, comments=comments, line_separator=line_separator, comment_prefix=comment_prefix, include_trailing_comma=include_trailing_comma, remove_comments=remove_comments, ) except ValueError: reject() @pytest.mark.parametrize("include_trailing_comma", [True, False]) def test_hanging_indent__with_include_trailing_comma__expect_same_result(include_trailing_comma): result = isort.wrap_modes.hanging_indent( statement="from datetime import ", imports=["datetime", "time", "timedelta", "timezone", "tzinfo"], white_space=" ", indent=" ", line_length=50, comments=[], line_separator="\n", comment_prefix=" #", include_trailing_comma=include_trailing_comma, remove_comments=False, ) assert result == "from datetime import datetime, time, timedelta, \\\n timezone, tzinfo" @given( statement=st.text(), imports=st.lists(st.text()), white_space=st.text(), indent=st.text(), line_length=st.integers(), comments=st.lists(st.text()), line_separator=st.text(), comment_prefix=st.text(), include_trailing_comma=st.booleans(), remove_comments=st.booleans(), ) def test_fuzz_hanging_indent_with_parentheses( statement, imports, white_space, indent, line_length, comments, line_separator, comment_prefix, include_trailing_comma, remove_comments, ): try: isort.wrap_modes.hanging_indent_with_parentheses( statement=statement, imports=imports, white_space=white_space, indent=indent, line_length=line_length, comments=comments, line_separator=line_separator, comment_prefix=comment_prefix, include_trailing_comma=include_trailing_comma, remove_comments=remove_comments, ) except ValueError: reject() @given( statement=st.text(), imports=st.lists(st.text()), white_space=st.text(), indent=st.text(), line_length=st.integers(), comments=st.lists(st.text()), line_separator=st.text(), comment_prefix=st.text(), include_trailing_comma=st.booleans(), remove_comments=st.booleans(), ) def test_fuzz_noqa( statement, imports, white_space, indent, line_length, comments, line_separator, comment_prefix, include_trailing_comma, remove_comments, ): try: isort.wrap_modes.noqa( statement=statement, imports=imports, white_space=white_space, indent=indent, line_length=line_length, comments=comments, line_separator=line_separator, comment_prefix=comment_prefix, include_trailing_comma=include_trailing_comma, remove_comments=remove_comments, ) except ValueError: reject() @given( statement=st.text(), imports=st.lists(st.text()), white_space=st.text(), indent=st.text(), line_length=st.integers(), comments=st.lists(st.text()), line_separator=st.text(), comment_prefix=st.text(), include_trailing_comma=st.booleans(), remove_comments=st.booleans(), ) def test_fuzz_vertical( statement, imports, white_space, indent, line_length, comments, line_separator, comment_prefix, include_trailing_comma, remove_comments, ): try: isort.wrap_modes.vertical( statement=statement, imports=imports, white_space=white_space, indent=indent, line_length=line_length, comments=comments, line_separator=line_separator, comment_prefix=comment_prefix, include_trailing_comma=include_trailing_comma, remove_comments=remove_comments, ) except ValueError: reject() @given( statement=st.text(), imports=st.lists(st.text()), white_space=st.text(), indent=st.text(), line_length=st.integers(), comments=st.lists(st.text()), line_separator=st.text(), comment_prefix=st.text(), include_trailing_comma=st.booleans(), remove_comments=st.booleans(), ) def test_fuzz_vertical_grid( statement, imports, white_space, indent, line_length, comments, line_separator, comment_prefix, include_trailing_comma, remove_comments, ): try: isort.wrap_modes.vertical_grid( statement=statement, imports=imports, white_space=white_space, indent=indent, line_length=line_length, comments=comments, line_separator=line_separator, comment_prefix=comment_prefix, include_trailing_comma=include_trailing_comma, remove_comments=remove_comments, ) except ValueError: reject() @given( statement=st.text(), imports=st.lists(st.text()), white_space=st.text(), indent=st.text(), line_length=st.integers(), comments=st.lists(st.text()), line_separator=st.text(), comment_prefix=st.text(), include_trailing_comma=st.booleans(), remove_comments=st.booleans(), ) def test_fuzz_vertical_grid_grouped( statement, imports, white_space, indent, line_length, comments, line_separator, comment_prefix, include_trailing_comma, remove_comments, ): try: isort.wrap_modes.vertical_grid_grouped( statement=statement, imports=imports, white_space=white_space, indent=indent, line_length=line_length, comments=comments, line_separator=line_separator, comment_prefix=comment_prefix, include_trailing_comma=include_trailing_comma, remove_comments=remove_comments, ) except ValueError: reject() @given( statement=st.text(), imports=st.lists(st.text()), white_space=st.text(), indent=st.text(), line_length=st.integers(), comments=st.lists(st.text()), line_separator=st.text(), comment_prefix=st.text(), include_trailing_comma=st.booleans(), remove_comments=st.booleans(), ) def test_fuzz_vertical_hanging_indent( statement, imports, white_space, indent, line_length, comments, line_separator, comment_prefix, include_trailing_comma, remove_comments, ): try: isort.wrap_modes.vertical_hanging_indent( statement=statement, imports=imports, white_space=white_space, indent=indent, line_length=line_length, comments=comments, line_separator=line_separator, comment_prefix=comment_prefix, include_trailing_comma=include_trailing_comma, remove_comments=remove_comments, ) except ValueError: reject() @given( statement=st.text(), imports=st.lists(st.text()), white_space=st.text(), indent=st.text(), line_length=st.integers(), comments=st.lists(st.text()), line_separator=st.text(), comment_prefix=st.text(), include_trailing_comma=st.booleans(), remove_comments=st.booleans(), ) def test_fuzz_vertical_hanging_indent_bracket( statement, imports, white_space, indent, line_length, comments, line_separator, comment_prefix, include_trailing_comma, remove_comments, ): try: isort.wrap_modes.vertical_hanging_indent_bracket( statement=statement, imports=imports, white_space=white_space, indent=indent, line_length=line_length, comments=comments, line_separator=line_separator, comment_prefix=comment_prefix, include_trailing_comma=include_trailing_comma, remove_comments=remove_comments, ) except ValueError: reject() @given( statement=st.text(), imports=st.lists(st.text()), white_space=st.text(), indent=st.text(), line_length=st.integers(), comments=st.lists(st.text()), line_separator=st.text(), comment_prefix=st.text(), include_trailing_comma=st.booleans(), remove_comments=st.booleans(), ) def test_fuzz_vertical_prefix_from_module_import( statement, imports, white_space, indent, line_length, comments, line_separator, comment_prefix, include_trailing_comma, remove_comments, ): try: isort.wrap_modes.vertical_prefix_from_module_import( statement=statement, imports=imports, white_space=white_space, indent=indent, line_length=line_length, comments=comments, line_separator=line_separator, comment_prefix=comment_prefix, include_trailing_comma=include_trailing_comma, remove_comments=remove_comments, ) except ValueError: reject() isort-6.0.1/tests/unit/utils.py0000644000000000000000000000154213615410400013433 0ustar00from io import BytesIO, StringIO, TextIOWrapper import isort class UnseekableTextIOWrapper(TextIOWrapper): def seek(self, *args, **kwargs): raise ValueError("underlying stream is not seekable") class UnreadableStream(StringIO): def readable(self, *args, **kwargs) -> bool: return False def as_stream(text: str) -> UnseekableTextIOWrapper: return UnseekableTextIOWrapper(BytesIO(text.encode("utf8"))) def isort_test(code: str, expected_output: str = "", **config): """Runs isort against the given code snippet and ensures that it gives consistent output across multiple runs, and if an expected_output is given - that it matches that. """ expected_output = expected_output or code output = isort.code(code, **config) assert output == expected_output assert output == isort.code(output, **config) isort-6.0.1/tests/unit/example_projects/namespaces/almost-implicit/.isort.cfg0000644000000000000000000000003213615410400024403 0ustar00[settings] src_paths=root isort-6.0.1/tests/unit/example_projects/namespaces/almost-implicit/root/y.py0000644000000000000000000000000013615410400024304 0ustar00isort-6.0.1/tests/unit/example_projects/namespaces/almost-implicit/root/nested/__init__.py0000644000000000000000000000000013615410400027055 0ustar00isort-6.0.1/tests/unit/example_projects/namespaces/almost-implicit/root/nested/x.py0000644000000000000000000000000013615410400025565 0ustar00isort-6.0.1/tests/unit/example_projects/namespaces/implicit/.isort.cfg0000644000000000000000000000003213615410400023106 0ustar00[settings] src_paths=root isort-6.0.1/tests/unit/example_projects/namespaces/implicit/root/nested/__init__.py0000644000000000000000000000000013615410400025560 0ustar00isort-6.0.1/tests/unit/example_projects/namespaces/implicit/root/nested/x.py0000644000000000000000000000000013615410400024270 0ustar00isort-6.0.1/tests/unit/example_projects/namespaces/none/.isort.cfg0000644000000000000000000000003213615410400022233 0ustar00[settings] src_paths=root isort-6.0.1/tests/unit/example_projects/namespaces/none/root/__init__.py0000644000000000000000000000000013615410400023423 0ustar00isort-6.0.1/tests/unit/example_projects/namespaces/none/root/nested/__init__.py0000644000000000000000000000000013615410400024705 0ustar00isort-6.0.1/tests/unit/example_projects/namespaces/pkg_resource/.isort.cfg0000644000000000000000000000003213615410400023764 0ustar00[settings] src_paths=root isort-6.0.1/tests/unit/example_projects/namespaces/pkg_resource/root/__init__.py0000644000000000000000000000007013615410400025163 0ustar00__import__("pkg_resources").declare_namespace(__name__) isort-6.0.1/tests/unit/example_projects/namespaces/pkg_resource/root/nested/__init__.py0000644000000000000000000000000013615410400026436 0ustar00isort-6.0.1/tests/unit/example_projects/namespaces/pkg_resource/root/nested/x.py0000644000000000000000000000000013615410400025146 0ustar00isort-6.0.1/tests/unit/example_projects/namespaces/pkgutil/.isort.cfg0000644000000000000000000000003213615410400022753 0ustar00[settings] src_paths=root isort-6.0.1/tests/unit/example_projects/namespaces/pkgutil/root/__init__.py0000644000000000000000000000010113615410400024145 0ustar00__path__ = __import__("pkgutil").extend_path(__path__, __name__) isort-6.0.1/tests/unit/example_projects/namespaces/pkgutil/root/nested/__init__.py0000644000000000000000000000000013615410400025425 0ustar00isort-6.0.1/tests/unit/example_projects/namespaces/pkgutil/root/nested/x.py0000644000000000000000000000000013615410400024135 0ustar00isort-6.0.1/tests/unit/example_projects/namespaces/weird_encoding/.isort.cfg0000644000000000000000000000003213615410400024254 0ustar00[settings] src_paths=root isort-6.0.1/tests/unit/example_projects/namespaces/weird_encoding/root/__init__.py0000644000000000000000000000012313615410400025452 0ustar00description = "基于FastAPI + Mysql的 TodoList" # Exception: UnicodeDecodeError isort-6.0.1/tests/unit/example_projects/namespaces/weird_encoding/root/nested/__init__.py0000644000000000000000000000000013615410400026726 0ustar00isort-6.0.1/tests/unit/profiles/__init__.py0000644000000000000000000000000013615410400015641 0ustar00isort-6.0.1/tests/unit/profiles/test_attrs.py0000644000000000000000000000346513615410400016320 0ustar00from functools import partial from ..utils import isort_test attrs_isort_test = partial(isort_test, profile="attrs") def test_attrs_code_snippet_one(): attrs_isort_test( """from __future__ import absolute_import, division, print_function import sys from functools import partial from . import converters, exceptions, filters, setters, validators from ._config import get_run_validators, set_run_validators from ._funcs import asdict, assoc, astuple, evolve, has, resolve_types from ._make import ( NOTHING, Attribute, Factory, attrib, attrs, fields, fields_dict, make_class, validate, ) from ._version_info import VersionInfo __version__ = "20.2.0.dev0" """ ) def test_attrs_code_snippet_two(): attrs_isort_test( """from __future__ import absolute_import, division, print_function import copy import linecache import sys import threading import uuid import warnings from operator import itemgetter from . import _config, setters from ._compat import ( PY2, isclass, iteritems, metadata_proxy, ordered_dict, set_closure_cell, ) from .exceptions import ( DefaultAlreadySetError, FrozenInstanceError, NotAnAttrsClassError, PythonTooOldError, UnannotatedAttributeError, ) # This is used at least twice, so cache it here. _obj_setattr = object.__setattr__ """ ) def test_attrs_code_snippet_three(): attrs_isort_test( ''' """ Commonly useful validators. """ from __future__ import absolute_import, division, print_function import re from ._make import _AndValidator, and_, attrib, attrs from .exceptions import NotCallableError __all__ = [ "and_", "deep_iterable", "deep_mapping", "in_", "instance_of", "is_callable", "matches_re", "optional", "provides", ] ''' ) isort-6.0.1/tests/unit/profiles/test_black.py0000644000000000000000000002377113615410400016241 0ustar00import black from black.report import NothingChanged import isort def black_format(code: str, is_pyi: bool = False, line_length: int = 88) -> str: """Formats the provided code snippet using black""" try: return black.format_file_contents( code, fast=True, mode=black.FileMode( is_pyi=is_pyi, line_length=line_length, ), ) except NothingChanged: return code def black_test(code: str, expected_output: str = "", *, is_pyi: bool = False, **config_kwargs): """Tests that the given code: - Behaves the same when formatted multiple times with isort. - Agrees with black formatting. - Matches the desired output or itself if none is provided. """ expected_output = expected_output or code config_kwargs = { "extension": "pyi" if is_pyi else None, "profile": "black", **config_kwargs, } # output should stay consistent over multiple runs output = isort.code(code, **config_kwargs) assert output == isort.code(code, **config_kwargs) # output should agree with black black_output = black_format(output, is_pyi=is_pyi) assert output == black_output # output should match expected output assert output == expected_output def test_black_snippet_one(): """Test consistent code formatting between isort and black for code snippet from black repository. See: https://github.com/psf/black/blob/master/tests/test_black.py """ black_test( """#!/usr/bin/env python3 import asyncio import logging from concurrent.futures import ThreadPoolExecutor from contextlib import contextmanager from dataclasses import replace from functools import partial import inspect from io import BytesIO, TextIOWrapper import os from pathlib import Path from platform import system import regex as re import sys from tempfile import TemporaryDirectory import types from typing import ( Any, BinaryIO, Callable, Dict, Generator, List, Tuple, Iterator, TypeVar, ) import unittest from unittest.mock import patch, MagicMock import click from click import unstyle from click.testing import CliRunner import black from black import Feature, TargetVersion try: import blackd from aiohttp.test_utils import AioHTTPTestCase, unittest_run_loop from aiohttp import web except ImportError: has_blackd_deps = False else: has_blackd_deps = True from pathspec import PathSpec # Import other test classes from .test_primer import PrimerCLITests # noqa: F401 DEFAULT_MODE = black.FileMode(experimental_string_processing=True) """, """#!/usr/bin/env python3 import asyncio import inspect import logging import os import sys import types import unittest from concurrent.futures import ThreadPoolExecutor from contextlib import contextmanager from dataclasses import replace from functools import partial from io import BytesIO, TextIOWrapper from pathlib import Path from platform import system from tempfile import TemporaryDirectory from typing import ( Any, BinaryIO, Callable, Dict, Generator, Iterator, List, Tuple, TypeVar, ) from unittest.mock import MagicMock, patch import black import click import regex as re from black import Feature, TargetVersion from click import unstyle from click.testing import CliRunner try: import blackd from aiohttp import web from aiohttp.test_utils import AioHTTPTestCase, unittest_run_loop except ImportError: has_blackd_deps = False else: has_blackd_deps = True from pathspec import PathSpec # Import other test classes from .test_primer import PrimerCLITests # noqa: F401 DEFAULT_MODE = black.FileMode(experimental_string_processing=True) """, ) def test_black_snippet_two(): """Test consistent code formatting between isort and black for code snippet from black repository. See: https://github.com/psf/black/blob/master/tests/test_primer.py """ black_test( '''#!/usr/bin/env python3 import asyncio import sys import unittest from contextlib import contextmanager from copy import deepcopy from io import StringIO from os import getpid from pathlib import Path from platform import system from subprocess import CalledProcessError from tempfile import TemporaryDirectory, gettempdir from typing import Any, Callable, Generator, Iterator, Tuple from unittest.mock import Mock, patch from click.testing import CliRunner from black_primer import cli, lib EXPECTED_ANALYSIS_OUTPUT = """\ -- primer results 📊 -- 68 / 69 succeeded (98.55%) ✅ 1 / 69 FAILED (1.45%) 💩 - 0 projects disabled by config - 0 projects skipped due to Python version - 0 skipped due to long checkout Failed projects: ## black: - Returned 69 - stdout: Black didn't work """ ''', '''#!/usr/bin/env python3 import asyncio import sys import unittest from contextlib import contextmanager from copy import deepcopy from io import StringIO from os import getpid from pathlib import Path from platform import system from subprocess import CalledProcessError from tempfile import TemporaryDirectory, gettempdir from typing import Any, Callable, Generator, Iterator, Tuple from unittest.mock import Mock, patch from black_primer import cli, lib from click.testing import CliRunner EXPECTED_ANALYSIS_OUTPUT = """-- primer results 📊 -- 68 / 69 succeeded (98.55%) ✅ 1 / 69 FAILED (1.45%) 💩 - 0 projects disabled by config - 0 projects skipped due to Python version - 0 skipped due to long checkout Failed projects: ## black: - Returned 69 - stdout: Black didn't work """ ''', ) def test_black_snippet_three(): """Test consistent code formatting between isort and black for code snippet from black repository. See: https://github.com/psf/black/blob/master/src/black/__init__.py """ black_test( """import ast import asyncio from abc import ABC, abstractmethod from collections import defaultdict from concurrent.futures import Executor, ThreadPoolExecutor, ProcessPoolExecutor from contextlib import contextmanager from datetime import datetime from enum import Enum from functools import lru_cache, partial, wraps import io import itertools import logging from multiprocessing import Manager, freeze_support import os from pathlib import Path import pickle import regex as re import signal import sys import tempfile import tokenize import traceback from typing import ( Any, Callable, Collection, Dict, Generator, Generic, Iterable, Iterator, List, Optional, Pattern, Sequence, Set, Sized, Tuple, Type, TypeVar, Union, cast, TYPE_CHECKING, ) from typing_extensions import Final from mypy_extensions import mypyc_attr from appdirs import user_cache_dir from dataclasses import dataclass, field, replace import click import toml from typed_ast import ast3, ast27 from pathspec import PathSpec # lib2to3 fork from blib2to3.pytree import Node, Leaf, type_repr from blib2to3 import pygram, pytree from blib2to3.pgen2 import driver, token from blib2to3.pgen2.grammar import Grammar from blib2to3.pgen2.parse import ParseError from _black_version import version as __version__ if TYPE_CHECKING: import colorama # noqa: F401 DEFAULT_LINE_LENGTH = 88 """, """import ast import asyncio import io import itertools import logging import os import pickle import signal import sys import tempfile import tokenize import traceback from abc import ABC, abstractmethod from collections import defaultdict from concurrent.futures import Executor, ProcessPoolExecutor, ThreadPoolExecutor from contextlib import contextmanager from dataclasses import dataclass, field, replace from datetime import datetime from enum import Enum from functools import lru_cache, partial, wraps from multiprocessing import Manager, freeze_support from pathlib import Path from typing import ( TYPE_CHECKING, Any, Callable, Collection, Dict, Generator, Generic, Iterable, Iterator, List, Optional, Pattern, Sequence, Set, Sized, Tuple, Type, TypeVar, Union, cast, ) import click import regex as re import toml from _black_version import version as __version__ from appdirs import user_cache_dir from blib2to3 import pygram, pytree from blib2to3.pgen2 import driver, token from blib2to3.pgen2.grammar import Grammar from blib2to3.pgen2.parse import ParseError # lib2to3 fork from blib2to3.pytree import Leaf, Node, type_repr from mypy_extensions import mypyc_attr from pathspec import PathSpec from typed_ast import ast3, ast27 from typing_extensions import Final if TYPE_CHECKING: import colorama # noqa: F401 DEFAULT_LINE_LENGTH = 88 """, ) def test_black_pyi_file(): """Test consistent code formatting between isort and black for `.pyi` files. black only allows no more than two consecutive blank lines in a `.pyi` file. """ black_test( """# comment import math from typing import Sequence import numpy as np def add(a: np.ndarray, b: np.ndarray) -> np.ndarray: ... def sub(a: np.ndarray, b: np.ndarray) -> np.ndarray: ... """, """# comment import math from typing import Sequence import numpy as np def add(a: np.ndarray, b: np.ndarray) -> np.ndarray: ... def sub(a: np.ndarray, b: np.ndarray) -> np.ndarray: ... """, is_pyi=False, lines_before_imports=2, lines_after_imports=2, ) black_test( """# comment import math from typing import Sequence import numpy as np def add(a: np.ndarray, b: np.ndarray) -> np.ndarray: ... def sub(a: np.ndarray, b: np.ndarray) -> np.ndarray: ... """, """# comment import math from typing import Sequence import numpy as np def add(a: np.ndarray, b: np.ndarray) -> np.ndarray: ... def sub(a: np.ndarray, b: np.ndarray) -> np.ndarray: ... """, is_pyi=True, lines_before_imports=2, # will be ignored lines_after_imports=2, # will be ignored ) def test_black_trailing_comma(): black_test( "from x import (a, b, c,)\n", """\ from x import ( a, b, c, ) """, ) isort-6.0.1/tests/unit/profiles/test_django.py0000644000000000000000000000723513615410400016424 0ustar00from functools import partial from ..utils import isort_test django_isort_test = partial(isort_test, profile="django", known_first_party=["django"]) def test_django_snippet_one(): django_isort_test( """import copy import inspect import warnings from functools import partialmethod from itertools import chain from django.apps import apps from django.conf import settings from django.core import checks from django.core.exceptions import ( NON_FIELD_ERRORS, FieldDoesNotExist, FieldError, MultipleObjectsReturned, ObjectDoesNotExist, ValidationError, ) from django.db import ( DEFAULT_DB_ALIAS, DJANGO_VERSION_PICKLE_KEY, DatabaseError, connection, connections, router, transaction, ) from django.db.models import ( NOT_PROVIDED, ExpressionWrapper, IntegerField, Max, Value, ) from django.db.models.constants import LOOKUP_SEP from django.db.models.constraints import CheckConstraint from django.db.models.deletion import CASCADE, Collector from django.db.models.fields.related import ( ForeignObjectRel, OneToOneField, lazy_related_operation, resolve_relation, ) from django.db.models.functions import Coalesce from django.db.models.manager import Manager from django.db.models.options import Options from django.db.models.query import Q from django.db.models.signals import ( class_prepared, post_init, post_save, pre_init, pre_save, ) from django.db.models.utils import make_model_tuple from django.utils.encoding import force_str from django.utils.hashable import make_hashable from django.utils.text import capfirst, get_text_list from django.utils.translation import gettext_lazy as _ from django.utils.version import get_version class Deferred: def __repr__(self): return '' def __str__(self): return ''""" ) def test_django_snippet_two(): django_isort_test( '''from django.utils.version import get_version VERSION = (3, 2, 0, 'alpha', 0) __version__ = get_version(VERSION) def setup(set_prefix=True): """ Configure the settings (this happens as a side effect of accessing the first setting), configure logging and populate the app registry. Set the thread-local urlresolvers script prefix if `set_prefix` is True. """ from django.apps import apps from django.conf import settings from django.urls import set_script_prefix from django.utils.log import configure_logging configure_logging(settings.LOGGING_CONFIG, settings.LOGGING) if set_prefix: set_script_prefix( '/' if settings.FORCE_SCRIPT_NAME is None else settings.FORCE_SCRIPT_NAME ) apps.populate(settings.INSTALLED_APPS)''' ) def test_django_snippet_three(): django_isort_test( """import cgi import codecs import copy import warnings from io import BytesIO from itertools import chain from urllib.parse import quote, urlencode, urljoin, urlsplit from django.conf import settings from django.core import signing from django.core.exceptions import ( DisallowedHost, ImproperlyConfigured, RequestDataTooBig, ) from django.core.files import uploadhandler from django.http.multipartparser import MultiPartParser, MultiPartParserError from django.utils.datastructures import ( CaseInsensitiveMapping, ImmutableList, MultiValueDict, ) from django.utils.deprecation import RemovedInDjango40Warning from django.utils.encoding import escape_uri_path, iri_to_uri from django.utils.functional import cached_property from django.utils.http import is_same_domain, limited_parse_qsl from django.utils.regex_helper import _lazy_re_compile from .multipartparser import parse_header RAISE_ERROR = object() class UnreadablePostError(OSError): pass""" ) isort-6.0.1/tests/unit/profiles/test_google.py0000644000000000000000000003210713615410400016432 0ustar00from functools import partial from ..utils import isort_test google_isort_test = partial(isort_test, profile="google") def test_google_code_snippet_shared_example(): """Tests snippet examples directly shared with the isort project. See: https://github.com/PyCQA/isort/issues/1486. """ google_isort_test( """import collections import cProfile """ ) google_isort_test( """from a import z from a.b import c from a.b import import_me """ ) def test_google_code_snippet_one(): google_isort_test( '''# coding=utf-8 # Copyright 2018 Google LLC # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # https://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. """JAX user-facing transformations and utilities. The transformations here mostly wrap internal transformations, providing convenience flags to control behavior and handling Python containers of arguments and outputs. The Python containers handled are pytrees (see tree_util.py), which include nested tuples/lists/dicts, where the leaves are arrays. """ # flake8: noqa: F401 import collections import functools import inspect import itertools as it import threading import weakref from typing import Any, Callable, Iterable, List, NamedTuple, Optional, Sequence, Tuple, TypeVar, Union from warnings import warn import numpy as np from contextlib import contextmanager, ExitStack from . import core from . import linear_util as lu from . import ad_util from . import dtypes from .core import eval_jaxpr from .api_util import (wraps, flatten_fun, apply_flat_fun, flatten_fun_nokwargs, flatten_fun_nokwargs2, argnums_partial, flatten_axes, donation_vector, rebase_donate_argnums) from .traceback_util import api_boundary from .tree_util import (tree_map, tree_flatten, tree_unflatten, tree_structure, tree_transpose, tree_leaves, tree_multimap, treedef_is_leaf, Partial) from .util import (unzip2, curry, partial, safe_map, safe_zip, prod, split_list, extend_name_stack, wrap_name, cache) from .lib import xla_bridge as xb from .lib import xla_client as xc # Unused imports to be exported from .lib.xla_bridge import (device_count, local_device_count, devices, local_devices, host_id, host_ids, host_count) from .abstract_arrays import ConcreteArray, ShapedArray, raise_to_shaped from .interpreters import partial_eval as pe from .interpreters import xla from .interpreters import pxla from .interpreters import ad from .interpreters import batching from .interpreters import masking from .interpreters import invertible_ad as iad from .interpreters.invertible_ad import custom_ivjp from .custom_derivatives import custom_jvp, custom_vjp from .config import flags, config, bool_env AxisName = Any # This TypeVar is used below to express the fact that function call signatures # are invariant under the jit, vmap, and pmap transformations. # Specifically, we statically assert that the return type is invariant. # Until PEP-612 is implemented, we cannot express the same invariance for # function arguments. # Note that the return type annotations will generally not strictly hold # in JIT internals, as Tracer values are passed through the function. # Should this raise any type errors for the tracing code in future, we can disable # type checking in parts of the tracing code, or remove these annotations. T = TypeVar("T") map = safe_map zip = safe_zip FLAGS = flags.FLAGS flags.DEFINE_bool("jax_disable_jit", bool_env("JAX_DISABLE_JIT", False), "Disable JIT compilation and just call original Python.") ''', '''# coding=utf-8 # Copyright 2018 Google LLC # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # https://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. """JAX user-facing transformations and utilities. The transformations here mostly wrap internal transformations, providing convenience flags to control behavior and handling Python containers of arguments and outputs. The Python containers handled are pytrees (see tree_util.py), which include nested tuples/lists/dicts, where the leaves are arrays. """ # flake8: noqa: F401 import collections from contextlib import contextmanager from contextlib import ExitStack import functools import inspect import itertools as it import threading from typing import Any, Callable, Iterable, List, NamedTuple, Optional, Sequence, Tuple, TypeVar, Union from warnings import warn import weakref import numpy as np from . import ad_util from . import core from . import dtypes from . import linear_util as lu from .abstract_arrays import ConcreteArray from .abstract_arrays import raise_to_shaped from .abstract_arrays import ShapedArray from .api_util import apply_flat_fun from .api_util import argnums_partial from .api_util import donation_vector from .api_util import flatten_axes from .api_util import flatten_fun from .api_util import flatten_fun_nokwargs from .api_util import flatten_fun_nokwargs2 from .api_util import rebase_donate_argnums from .api_util import wraps from .config import bool_env from .config import config from .config import flags from .core import eval_jaxpr from .custom_derivatives import custom_jvp from .custom_derivatives import custom_vjp from .interpreters import ad from .interpreters import batching from .interpreters import invertible_ad as iad from .interpreters import masking from .interpreters import partial_eval as pe from .interpreters import pxla from .interpreters import xla from .interpreters.invertible_ad import custom_ivjp from .lib import xla_bridge as xb from .lib import xla_client as xc # Unused imports to be exported from .lib.xla_bridge import device_count from .lib.xla_bridge import devices from .lib.xla_bridge import host_count from .lib.xla_bridge import host_id from .lib.xla_bridge import host_ids from .lib.xla_bridge import local_device_count from .lib.xla_bridge import local_devices from .traceback_util import api_boundary from .tree_util import Partial from .tree_util import tree_flatten from .tree_util import tree_leaves from .tree_util import tree_map from .tree_util import tree_multimap from .tree_util import tree_structure from .tree_util import tree_transpose from .tree_util import tree_unflatten from .tree_util import treedef_is_leaf from .util import cache from .util import curry from .util import extend_name_stack from .util import partial from .util import prod from .util import safe_map from .util import safe_zip from .util import split_list from .util import unzip2 from .util import wrap_name AxisName = Any # This TypeVar is used below to express the fact that function call signatures # are invariant under the jit, vmap, and pmap transformations. # Specifically, we statically assert that the return type is invariant. # Until PEP-612 is implemented, we cannot express the same invariance for # function arguments. # Note that the return type annotations will generally not strictly hold # in JIT internals, as Tracer values are passed through the function. # Should this raise any type errors for the tracing code in future, we can disable # type checking in parts of the tracing code, or remove these annotations. T = TypeVar("T") map = safe_map zip = safe_zip FLAGS = flags.FLAGS flags.DEFINE_bool("jax_disable_jit", bool_env("JAX_DISABLE_JIT", False), "Disable JIT compilation and just call original Python.") ''', ) def test_google_code_snippet_two(): google_isort_test( """#!/usr/bin/env python # In[ ]: # coding: utf-8 ###### Searching and Downloading Google Images to the local disk ###### # Import Libraries import sys version = (3, 0) cur_version = sys.version_info if cur_version >= version: # If the Current Version of Python is 3.0 or above import urllib.request from urllib.request import Request, urlopen from urllib.request import URLError, HTTPError from urllib.parse import quote import http.client from http.client import IncompleteRead, BadStatusLine http.client._MAXHEADERS = 1000 else: # If the Current Version of Python is 2.x import urllib2 from urllib2 import Request, urlopen from urllib2 import URLError, HTTPError from urllib import quote import httplib from httplib import IncompleteRead, BadStatusLine httplib._MAXHEADERS = 1000 import time # Importing the time library to check the time of code execution import os import argparse import ssl import datetime import json import re import codecs import socket""", """#!/usr/bin/env python # In[ ]: # coding: utf-8 ###### Searching and Downloading Google Images to the local disk ###### # Import Libraries import sys version = (3, 0) cur_version = sys.version_info if cur_version >= version: # If the Current Version of Python is 3.0 or above import http.client from http.client import BadStatusLine from http.client import IncompleteRead from urllib.parse import quote import urllib.request from urllib.request import HTTPError from urllib.request import Request from urllib.request import URLError from urllib.request import urlopen http.client._MAXHEADERS = 1000 else: # If the Current Version of Python is 2.x from urllib import quote import httplib from httplib import BadStatusLine from httplib import IncompleteRead import urllib2 from urllib2 import HTTPError from urllib2 import Request from urllib2 import URLError from urllib2 import urlopen httplib._MAXHEADERS = 1000 import argparse import codecs import datetime import json import os import re import socket import ssl import time # Importing the time library to check the time of code execution """, ) def test_code_snippet_three(): google_isort_test( '''# Copyright 2019 Google LLC # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. """Monitoring.""" # pylint: disable=invalid-name # TODO(ochang): Remove V3 from names once all metrics are migrated to # stackdriver. from builtins import object from builtins import range from builtins import str import bisect import collections import functools import itertools import re import six import threading import time try: from google.cloud import monitoring_v3 except (ImportError, RuntimeError): monitoring_v3 = None from google.api_core import exceptions from google.api_core import retry from base import errors from base import utils from config import local_config from google_cloud_utils import compute_metadata from google_cloud_utils import credentials from metrics import logs from system import environment''', '''# Copyright 2019 Google LLC # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. """Monitoring.""" # pylint: disable=invalid-name # TODO(ochang): Remove V3 from names once all metrics are migrated to # stackdriver. import bisect from builtins import object from builtins import range from builtins import str import collections import functools import itertools import re import threading import time import six try: from google.cloud import monitoring_v3 except (ImportError, RuntimeError): monitoring_v3 = None from base import errors from base import utils from config import local_config from google.api_core import exceptions from google.api_core import retry from google_cloud_utils import compute_metadata from google_cloud_utils import credentials from metrics import logs from system import environment ''', ) isort-6.0.1/tests/unit/profiles/test_hug.py0000644000000000000000000000561113615410400015741 0ustar00from functools import partial from ..utils import isort_test hug_isort_test = partial(isort_test, profile="hug", known_first_party=["hug"]) def test_hug_code_snippet_one(): hug_isort_test( ''' from __future__ import absolute_import import asyncio import sys from collections import OrderedDict, namedtuple from distutils.util import strtobool from functools import partial from itertools import chain from types import ModuleType from wsgiref.simple_server import make_server import falcon from falcon import HTTP_METHODS import hug.defaults import hug.output_format from hug import introspect from hug._version import current INTRO = """ /#######################################################################\\ `.----``..-------..``.----. :/:::::--:---------:--::::://. .+::::----##/-/oo+:-##----::::// `//::-------/oosoo-------::://. ## ## ## ## ##### .-:------./++o/o-.------::-` ``` ## ## ## ## ## `----.-./+o+:..----. `.:///. ######## ## ## ## ``` `----.-::::::------ `.-:::://. ## ## ## ## ## #### ://::--.``` -:``...-----...` `:--::::::-.` ## ## ## ## ## ## :/:::::::::-:- ````` .:::::-.` ## ## #### ###### ``.--:::::::. .:::.` ``..::. .:: EMBRACE THE APIs OF THE FUTURE ::- .:- -::` ::- VERSION {0} `::- -::` -::-` -::- \\########################################################################/ Copyright (C) 2016 Timothy Edmund Crosley Under the MIT License """.format( current )''' ) def test_hug_code_snippet_two(): hug_isort_test( """from __future__ import absolute_import import functools from collections import namedtuple from falcon import HTTP_METHODS import hug.api import hug.defaults import hug.output_format from hug import introspect from hug.format import underscore def default_output_format( content_type="application/json", apply_globally=False, api=None, cli=False, http=True ): """ ) def test_hug_code_snippet_three(): hug_isort_test( """from __future__ import absolute_import import argparse import asyncio import os import sys from collections import OrderedDict from functools import lru_cache, partial, wraps import falcon from falcon import HTTP_BAD_REQUEST import hug._empty as empty import hug.api import hug.output_format import hug.types as types from hug import introspect from hug.exceptions import InvalidTypeData from hug.format import parse_content_type from hug.types import ( MarshmallowInputSchema, MarshmallowReturnSchema, Multiple, OneOf, SmartBoolean, Text, text, ) DOC_TYPE_MAP = {str: "String", bool: "Boolean", list: "Multiple", int: "Integer", float: "Float"} """ ) isort-6.0.1/tests/unit/profiles/test_open_stack.py0000644000000000000000000000710313615410400017302 0ustar00from functools import partial from ..utils import isort_test open_stack_isort_test = partial(isort_test, profile="open_stack") def test_open_stack_code_snippet_one(): open_stack_isort_test( """import httplib import logging import random import StringIO import time import unittest import eventlet import webob.exc import nova.api.ec2 from nova.api import manager from nova.api import openstack from nova.auth import users from nova.endpoint import cloud import nova.flags from nova.i18n import _ from nova.i18n import _LC from nova import test """, known_first_party=["nova"], py_version="2", order_by_type=False, ) def test_open_stack_code_snippet_two(): open_stack_isort_test( """# Copyright 2011 VMware, Inc # All Rights Reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. You may obtain # a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations # under the License. import inspect import os import random from neutron_lib.callbacks import events from neutron_lib.callbacks import registry from neutron_lib.callbacks import resources from neutron_lib import context from neutron_lib.db import api as session from neutron_lib.plugins import directory from neutron_lib import rpc as n_rpc from oslo_concurrency import processutils from oslo_config import cfg from oslo_log import log as logging from oslo_messaging import server as rpc_server from oslo_service import loopingcall from oslo_service import service as common_service from oslo_utils import excutils from oslo_utils import importutils import psutil from neutron.common import config from neutron.common import profiler from neutron.conf import service from neutron import worker as neutron_worker from neutron import wsgi service.register_service_opts(service.SERVICE_OPTS) """, known_first_party=["neutron"], ) def test_open_stack_code_snippet_three(): open_stack_isort_test( """ # Copyright 2013 Red Hat, Inc. # # Licensed under the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. You may obtain # a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations # under the License. import functools from oslo_log import log as logging import oslo_messaging as messaging from oslo_messaging.rpc import dispatcher from oslo_serialization import jsonutils from oslo_service import periodic_task from oslo_utils import importutils import six import nova.conf import nova.context import nova.exception from nova.i18n import _ __all__ = [ 'init', 'cleanup', 'set_defaults', 'add_extra_exmods', 'clear_extra_exmods', 'get_allowed_exmods', 'RequestContextSerializer', 'get_client', 'get_server', 'get_notifier', ] profiler = importutils.try_import("osprofiler.profiler") """, known_first_party=["nova"], ) isort-6.0.1/tests/unit/profiles/test_plone.py0000644000000000000000000000435013615410400016272 0ustar00from functools import partial from ..utils import isort_test plone_isort_test = partial(isort_test, profile="plone") def test_plone_code_snippet_one(): plone_isort_test( """# -*- coding: utf-8 -*- from plone.app.multilingual.testing import PLONE_APP_MULTILINGUAL_PRESET_FIXTURE # noqa from plone.app.robotframework.testing import REMOTE_LIBRARY_BUNDLE_FIXTURE from plone.app.testing import FunctionalTesting from plone.app.testing import IntegrationTesting from plone.app.testing import PloneWithPackageLayer from plone.testing import z2 import plone.app.multilingualindexes PAMI_FIXTURE = PloneWithPackageLayer( bases=(PLONE_APP_MULTILINGUAL_PRESET_FIXTURE,), name="PAMILayer:Fixture", gs_profile_id="plone.app.multilingualindexes:default", zcml_package=plone.app.multilingualindexes, zcml_filename="configure.zcml", additional_z2_products=["plone.app.multilingualindexes"], ) """ ) def test_plone_code_snippet_two(): plone_isort_test( """# -*- coding: utf-8 -*- from Acquisition import aq_base from App.class_init import InitializeClass from App.special_dtml import DTMLFile from BTrees.OOBTree import OOTreeSet from logging import getLogger from plone import api from plone.app.multilingual.events import ITranslationRegisteredEvent from plone.app.multilingual.interfaces import ITG from plone.app.multilingual.interfaces import ITranslatable from plone.app.multilingual.interfaces import ITranslationManager from plone.app.multilingualindexes.utils import get_configuration from plone.indexer.interfaces import IIndexableObject from Products.CMFPlone.utils import safe_hasattr from Products.DateRecurringIndex.index import DateRecurringIndex from Products.PluginIndexes.common.UnIndex import UnIndex from Products.ZCatalog.Catalog import Catalog from ZODB.POSException import ConflictError from zope.component import getMultiAdapter from zope.component import queryAdapter from zope.globalrequest import getRequest logger = getLogger(__name__) """ ) def test_plone_code_snippet_three(): plone_isort_test( """# -*- coding: utf-8 -*- from plone.app.querystring.interfaces import IQueryModifier from zope.interface import provider import logging logger = logging.getLogger(__name__) """ ) isort-6.0.1/tests/unit/profiles/test_pycharm.py0000644000000000000000000000214113615410400016614 0ustar00from functools import partial from ..utils import isort_test pycharm_isort_test = partial(isort_test, profile="pycharm") def test_pycharm_snippet_one(): pycharm_isort_test( """import shutil import sys from io import StringIO from pathlib import Path from typing import ( Optional, TextIO, Union, cast ) from warnings import warn from isort import core from . import io from .exceptions import ( ExistingSyntaxErrors, FileSkipComment, FileSkipSetting, IntroducedSyntaxErrors ) from .format import ( ask_whether_to_apply_changes_to_file, create_terminal_printer, show_unified_diff ) from .io import Empty from .place import module as place_module # noqa: F401 from .place import module_with_reason as place_module_with_reason # noqa: F401 from .settings import ( DEFAULT_CONFIG, Config ) def sort_code_string( code: str, extension: Optional[str] = None, config: Config = DEFAULT_CONFIG, file_path: Optional[Path] = None, disregard_skip: bool = False, show_diff: Union[bool, TextIO] = False, **config_kwargs, ): """ ) isort-6.0.1/tests/unit/profiles/test_wemake.py0000644000000000000000000000600613615410400016426 0ustar00"""A set of test cases for the wemake isort profile. Snippets are taken directly from the wemake-python-styleguide project here: https://github.com/wemake-services/wemake-python-styleguide """ from functools import partial from ..utils import isort_test wemake_isort_test = partial( isort_test, profile="wemake", known_first_party=["wemake_python_styleguide"] ) def test_wemake_snippet_one(): wemake_isort_test( """ import ast import tokenize import traceback from typing import ClassVar, Iterator, Sequence, Type from flake8.options.manager import OptionManager from typing_extensions import final from wemake_python_styleguide import constants, types from wemake_python_styleguide import version as pkg_version from wemake_python_styleguide.options.config import Configuration from wemake_python_styleguide.options.validation import validate_options from wemake_python_styleguide.presets.types import file_tokens as tokens_preset from wemake_python_styleguide.presets.types import filename as filename_preset from wemake_python_styleguide.presets.types import tree as tree_preset from wemake_python_styleguide.transformations.ast_tree import transform from wemake_python_styleguide.violations import system from wemake_python_styleguide.visitors import base VisitorClass = Type[base.BaseVisitor] """ ) def test_wemake_snippet_two(): wemake_isort_test( """ from collections import defaultdict from typing import ClassVar, DefaultDict, List from flake8.formatting.base import BaseFormatter from flake8.statistics import Statistics from flake8.style_guide import Violation from pygments import highlight from pygments.formatters import TerminalFormatter from pygments.lexers import PythonLexer from typing_extensions import Final from wemake_python_styleguide.version import pkg_version #: That url is generated and hosted by Sphinx. DOCS_URL_TEMPLATE: Final = ( 'https://wemake-python-stylegui.de/en/{0}/pages/usage/violations/' ) """ ) def test_wemake_snippet_three(): wemake_isort_test( """ import ast from pep8ext_naming import NamingChecker from typing_extensions import final from wemake_python_styleguide.transformations.ast.bugfixes import ( fix_async_offset, fix_line_number, ) from wemake_python_styleguide.transformations.ast.enhancements import ( set_if_chain, set_node_context, ) @final class _ClassVisitor(ast.NodeVisitor): ... """ ) def test_wemake_snippet_four(): """80 line length should not be fixed""" wemake_isort_test( """ from typing import Iterable, Iterator, Optional, Sequence, Tuple, TypeVar, Union """, """ from typing import Iterable, Iterator, Optional, Sequence, Tuple, TypeVar, Union """, ) def test_wemake_snippet_five(): """81 line length should be fixed""" wemake_isort_test( """ from typing import Iterable, Iterator, Optional, Sequence, Tuple, TypeVar, Union1 """, """ from typing import ( Iterable, Iterator, Optional, Sequence, Tuple, TypeVar, Union1, ) """, ) isort-6.0.1/.gitignore0000644000000000000000000000133313615410400011566 0ustar00*.py[cod] __pycache__ .DS_Store # C extensions *.so # Packages *.egg *.egg-info .eggs build eggs parts var sdist develop-eggs .installed.cfg lib lib64 MANIFEST .eggs # Installer logs pip-log.txt npm-debug.log # Unit test / coverage reports .coverage .coverage.* coverage.xml .pytest_cache .tox nosetests.xml htmlcov .cache .pytest_cache/ .hypothesis/ # Translations *.mo # Mr Developer .mr.developer.cfg .project .pydevproject # SQLite test_exp_framework # npm node_modules/ # dolphin .directory libpeerconnection.log # setuptools dist # IDE Files atlassian-ide-plugin.xml .idea/ *.swp *.kate-swp .ropeproject/ .vscode # pip pip-selfcheck.json # Python3 Venv Files .python-version .venv/ pyvenv.cfg # mypy .mypy_cache isort-6.0.1/LICENSE0000644000000000000000000000210113615410400010575 0ustar00The MIT License (MIT) Copyright (c) 2013 Timothy Edmund Crosley Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. isort-6.0.1/README.md0000644000000000000000000002435713615410400011070 0ustar00[![isort - isort your imports, so you don't have to.](https://raw.githubusercontent.com/pycqa/isort/main/art/logo_large.png)](https://pycqa.github.io/isort/) ------------------------------------------------------------------------ [![PyPI version](https://badge.fury.io/py/isort.svg)](https://badge.fury.io/py/isort) [![Test](https://github.com/PyCQA/isort/actions/workflows/test.yml/badge.svg)](https://github.com/PyCQA/isort/actions/workflows/test.yml) [![Lint](https://github.com/PyCQA/isort/actions/workflows/lint.yml/badge.svg)](https://github.com/PyCQA/isort/actions/workflows/lint.yml) [![Code coverage Status](https://codecov.io/gh/pycqa/isort/branch/main/graph/badge.svg)](https://codecov.io/gh/pycqa/isort) [![License](https://img.shields.io/github/license/mashape/apistatus.svg)](https://pypi.org/project/isort/) [![Join the chat at https://gitter.im/timothycrosley/isort](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/timothycrosley/isort?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) [![Downloads](https://pepy.tech/badge/isort)](https://pepy.tech/project/isort) [![Code style: black](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/psf/black) [![Imports: isort](https://img.shields.io/badge/%20imports-isort-%231674b1?style=flat&labelColor=ef8336)](https://pycqa.github.io/isort/) [![DeepSource](https://static.deepsource.io/deepsource-badge-light-mini.svg)](https://deepsource.io/gh/pycqa/isort/?ref=repository-badge) _________________ [Read Latest Documentation](https://pycqa.github.io/isort/) - [Browse GitHub Code Repository](https://github.com/pycqa/isort/) _________________ isort your imports, so you don't have to. isort is a Python utility / library to sort imports alphabetically and automatically separate into sections and by type. It provides a command line utility, Python library and [plugins for various editors](https://github.com/pycqa/isort/wiki/isort-Plugins) to quickly sort all your imports. It requires Python 3.9+ to run but supports formatting Python 2 code too. - [Try isort now from your browser!](https://pycqa.github.io/isort/docs/quick_start/0.-try.html) - [Using black? See the isort and black compatibility guide.](https://pycqa.github.io/isort/docs/configuration/black_compatibility.html) - [isort has official support for pre-commit!](https://pycqa.github.io/isort/docs/configuration/pre-commit.html) ![Example Usage](https://raw.github.com/pycqa/isort/main/example.gif) Before isort: ```python from my_lib import Object import os from my_lib import Object3 from my_lib import Object2 import sys from third_party import lib15, lib1, lib2, lib3, lib4, lib5, lib6, lib7, lib8, lib9, lib10, lib11, lib12, lib13, lib14 import sys from __future__ import absolute_import from third_party import lib3 print("Hey") print("yo") ``` After isort: ```python from __future__ import absolute_import import os import sys from third_party import (lib1, lib2, lib3, lib4, lib5, lib6, lib7, lib8, lib9, lib10, lib11, lib12, lib13, lib14, lib15) from my_lib import Object, Object2, Object3 print("Hey") print("yo") ``` ## Installing isort Installing isort is as simple as: ```bash pip install isort ``` ## Using isort **From the command line**: To run on specific files: ```bash isort mypythonfile.py mypythonfile2.py ``` To apply recursively: ```bash isort . ``` If [globstar](https://www.gnu.org/software/bash/manual/html_node/The-Shopt-Builtin.html) is enabled, `isort .` is equivalent to: ```bash isort **/*.py ``` To view proposed changes without applying them: ```bash isort mypythonfile.py --diff ``` Finally, to atomically run isort against a project, only applying changes if they don't introduce syntax errors: ```bash isort --atomic . ``` (Note: this is disabled by default, as it prevents isort from running against code written using a different version of Python.) **From within Python**: ```python import isort isort.file("pythonfile.py") ``` or: ```python import isort sorted_code = isort.code("import b\nimport a\n") ``` ## Installing isort's for your preferred text editor Several plugins have been written that enable to use isort from within a variety of text-editors. You can find a full list of them [on the isort wiki](https://github.com/pycqa/isort/wiki/isort-Plugins). Additionally, I will enthusiastically accept pull requests that include plugins for other text editors and add documentation for them as I am notified. ## Multi line output modes You will notice above the \"multi\_line\_output\" setting. This setting defines how from imports wrap when they extend past the line\_length limit and has [12 possible settings](https://pycqa.github.io/isort/docs/configuration/multi_line_output_modes.html). ## Indentation To change the how constant indents appear - simply change the indent property with the following accepted formats: - Number of spaces you would like. For example: 4 would cause standard 4 space indentation. - Tab - A verbatim string with quotes around it. For example: ```python " " ``` is equivalent to 4. For the import styles that use parentheses, you can control whether or not to include a trailing comma after the last import with the `include_trailing_comma` option (defaults to `False`). ## Intelligently Balanced Multi-line Imports As of isort 3.1.0 support for balanced multi-line imports has been added. With this enabled isort will dynamically change the import length to the one that produces the most balanced grid, while staying below the maximum import length defined. Example: ```python from __future__ import (absolute_import, division, print_function, unicode_literals) ``` Will be produced instead of: ```python from __future__ import (absolute_import, division, print_function, unicode_literals) ``` To enable this set `balanced_wrapping` to `True` in your config or pass the `-e` option into the command line utility. ## Custom Sections and Ordering isort provides configuration options to change almost every aspect of how imports are organized, ordered, or grouped together in sections. [Click here](https://pycqa.github.io/isort/docs/configuration/custom_sections_and_ordering.html) for an overview of all these options. ## Skip processing of imports (outside of configuration) To make isort ignore a single import simply add a comment at the end of the import line containing the text `isort:skip`: ```python import module # isort:skip ``` or: ```python from xyz import (abc, # isort:skip yo, hey) ``` To make isort skip an entire file simply add `isort:skip_file` to the module's doc string: ```python """ my_module.py Best module ever isort:skip_file """ import b import a ``` ## Adding or removing an import from multiple files isort can be ran or configured to add / remove imports automatically. [See a complete guide here.](https://pycqa.github.io/isort/docs/configuration/add_or_remove_imports.html) ## Using isort to verify code The `--check-only` option ------------------------- isort can also be used to verify that code is correctly formatted by running it with `-c`. Any files that contain incorrectly sorted and/or formatted imports will be outputted to `stderr`. ```bash isort **/*.py -c -v SUCCESS: /home/timothy/Projects/Open_Source/isort/isort_kate_plugin.py Everything Looks Good! ERROR: /home/timothy/Projects/Open_Source/isort/isort/isort.py Imports are incorrectly sorted. ``` One great place this can be used is with a pre-commit git hook, such as this one by \@acdha: This can help to ensure a certain level of code quality throughout a project. ## Git hook isort provides a hook function that can be integrated into your Git pre-commit script to check Python code before committing. [More info here.](https://pycqa.github.io/isort/docs/configuration/git_hook.html) ## Setuptools integration Upon installation, isort enables a `setuptools` command that checks Python files declared by your project. [More info here.](https://pycqa.github.io/isort/docs/configuration/setuptools_integration.html) ## Spread the word [![Imports: isort](https://img.shields.io/badge/%20imports-isort-%231674b1?style=flat&labelColor=ef8336)](https://pycqa.github.io/isort/) Place this badge at the top of your repository to let others know your project uses isort. For README.md: ```markdown [![Imports: isort](https://img.shields.io/badge/%20imports-isort-%231674b1?style=flat&labelColor=ef8336)](https://pycqa.github.io/isort/) ``` Or README.rst: ```rst .. image:: https://img.shields.io/badge/%20imports-isort-%231674b1?style=flat&labelColor=ef8336 :target: https://pycqa.github.io/isort/ ``` ## Security contact information To report a security vulnerability, please use the [Tidelift security contact](https://tidelift.com/security). Tidelift will coordinate the fix and disclosure. ## Why isort? isort simply stands for import sort. It was originally called "sortImports" however I got tired of typing the extra characters and came to the realization camelCase is not pythonic. I wrote isort because in an organization I used to work in the manager came in one day and decided all code must have alphabetically sorted imports. The code base was huge - and he meant for us to do it by hand. However, being a programmer - I\'m too lazy to spend 8 hours mindlessly performing a function, but not too lazy to spend 16 hours automating it. I was given permission to open source sortImports and here we are :) ------------------------------------------------------------------------ [Get professionally supported isort with the Tidelift Subscription](https://tidelift.com/subscription/pkg/pypi-isort?utm_source=pypi-isort&utm_medium=referral&utm_campaign=readme) Professional support for isort is available as part of the [Tidelift Subscription](https://tidelift.com/subscription/pkg/pypi-isort?utm_source=pypi-isort&utm_medium=referral&utm_campaign=readme). Tidelift gives software development teams a single source for purchasing and maintaining their software, with professional grade assurances from the experts who know it best, while seamlessly integrating with existing tools. ------------------------------------------------------------------------ Thanks and I hope you find isort useful! ~Timothy Crosley isort-6.0.1/pyproject.toml0000644000000000000000000001243513615410400012517 0ustar00[tool.black] line-length = 100 [project] name = "isort" dynamic = ["version"] description = "A Python utility / library to sort Python imports." authors = [{name = "Timothy Crosley", email = "timothy.crosley@gmail.com"}, {name = "staticdev", email = "staticdev-support@proton.me"}] license = "MIT" readme = "README.md" repository = "https://github.com/pycqa/isort" homepage = "https://pycqa.github.io/isort/" documentation = "https://pycqa.github.io/isort/" keywords = ["Refactor", "Lint", "Imports", "Sort", "Clean"] classifiers = [ "Development Status :: 6 - Mature", "Intended Audience :: Developers", "Natural Language :: English", "Environment :: Console", "License :: OSI Approved :: MIT License", "Programming Language :: Python", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3.9", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", "Programming Language :: Python :: 3.13", "Programming Language :: Python :: 3 :: Only", "Programming Language :: Python :: Implementation :: CPython", "Programming Language :: Python :: Implementation :: PyPy", "Topic :: Software Development :: Libraries", "Topic :: Utilities", ] urls = { changelog = "https://github.com/PyCQA/isort/releases" } include = [ { path = "tests", format = "sdist" }, { path = "ACKNOWLEDGEMENTS.md", format = "sdist" }, { path = "LICENSE", format = "sdist" }, ] requires-python = ">=3.9.0" dependencies = [] [tool.hatch.version] source = "vcs" [tool.hatch.version.raw-options] local_scheme = "no-local-version" [project.scripts] isort = "isort.main:main" isort-identify-imports = "isort.main:identify_imports_main" [project.entry-points."distutils.commands"] isort = "isort.setuptools_commands:ISortCommand" [project.entry-points."pylama.linter"] isort = "isort.pylama_isort:Linter" [project.optional-dependencies] colors = ["colorama"] plugins = ["setuptools"] [tool.coverage.paths] source = [ "isort/", ".tox/*/lib/python*/site-packages/isort/", ".tox/*/lib/site-packages/isort/" ] tests = ["tests", "*/tests"] [tool.coverage.run] branch = true source = ["isort", "tests"] omit = [ "isort/_vendored/*", "tests/*", "isort/deprecated/*", ] [tool.coverage.report] show_missing = true fail_under = 99 exclude_lines = [ "pragma: no cover", "except ImportError:", "if TYPE_CHECKING:", "if __name__ == .__main__.:", "raise NotImplementedError", ] [tool.portray.mkdocs] edit_uri = "https://github.com/pycqa/isort/edit/main/" extra_css = ["art/stylesheets/extra.css"] [tool.portray.mkdocs.theme] name = "material" favicon = "art/logo.png" logo = "art/logo.png" palette = {scheme = "isort"} [build-system] requires = ["hatchling", "hatch-vcs"] build-backend = "hatchling.build" [dependency-groups] dev = [ "bandit>=1.7.7", "black>=24.3.0", "colorama>=0.4.6", "coverage[toml]>=6.5.0", "cruft>=2.12.0", "example-isort-sorting-plugin>=0.1.0", "example-shared-isort-profile>=0.1.0", "flake8>=3.8.4", "flake8-bugbear>=22.12.12", "flake8-pyproject>=1.2.3", "hatch>=1.14.0", "httpx>=0.13.3", "hypothesis>=6.10.1", "hypothesmith>=0.1.3", "libcst>=0.3.18", "mypy>=1.14.1", "mypy-extensions>=0.4.3", "pep8-naming>=0.8.2", "pip>=21.1.1", "pip_api>=0.0.12", "pipreqs>=0.4.9", "portray>=1.8.0", "pre-commit>=2.13.0", "pylama>=7.7", "pytest>=7.4.2", "pytest-benchmark>=3.4.1", "pytest-mock>=1.10", "requirementslib>=1.5", "ruff>=0.9.6", "stdlibs>=2024.10.21.16", "toml>=0.10.2", "types-colorama>=0.4.2", "types-setuptools>=70.0.0.20240523", "types-toml>=0.1.3", "vulture>=1.0", ] [tool.flake8] max-line-length = 100 # Ignore non PEP 8 compliant rules as suggested by black # E203: https://github.com/psf/black/blob/3fab5ade71bccf80ae0a5af76729099869adea56/docs/the_black_code_style/current_style.md#slices extend-ignore = [ "E203" ] exclude = "_vendored" per-file-ignores = [ "tests/unit/example_crlf_file.py:F401", "tests/unit/profiles/test_black.py:E501", "tests/unit/test_regressions.py:E501", ] [tool.mypy] python_version = 3.9 strict = true follow_imports = "silent" exclude = "isort/_vendored|tests/unit/example_projects|tests/unit/example_crlf_file.py" [[tool.mypy.overrides]] module = "tests.*" allow_untyped_defs = true allow_incomplete_defs = true allow_untyped_calls = true [tool.ruff] line-length = 100 lint.select = [ "ASYNC", "B", "C4", "C90", "E", "F", "FLY", "PERF", "PIE", "PLC", "PLE", "PT", "RUF", "S", "UP", "W", ] lint.ignore = [ "B904", "E501", "PERF203", "RUF100", "UP006", "UP035", ] lint.exclude = [ "isort/_vendored/*" ] lint.mccabe.max-complexity = 91 # Default is 10 [tool.ruff.lint.per-file-ignores] "isort/deprecated/finders.py" = [ "UP034" ] "isort/hooks.py" = [ "S603" ] "isort/output.py" = [ "PLC0206" ] "isort/settings.py" = [ "PLC0414", "S603", "S607" ] "isort/setuptools_commands.py" = [ "RUF012" ] "tests/*" = [ "RUF001", "S" ] "tests/unit/example_crlf_file.py" = [ "F401" ] "tests/unit/test_wrap_modes.py" = [ "PIE804" ] [tool.isort] profile = "hug" src_paths = ["isort", "tests"] skip = [ "tests/unit/example_crlf_file.py" ] isort-6.0.1/PKG-INFO0000644000000000000000000002715513615410400010705 0ustar00Metadata-Version: 2.4 Name: isort Version: 6.0.1 Summary: A Python utility / library to sort Python imports. Project-URL: changelog, https://github.com/PyCQA/isort/releases Author-email: Timothy Crosley , staticdev License-Expression: MIT License-File: LICENSE Keywords: Clean,Imports,Lint,Refactor,Sort Classifier: Development Status :: 6 - Mature Classifier: Environment :: Console Classifier: Intended Audience :: Developers Classifier: License :: OSI Approved :: MIT License Classifier: Natural Language :: English Classifier: Programming Language :: Python Classifier: Programming Language :: Python :: 3 Classifier: Programming Language :: Python :: 3 :: Only Classifier: Programming Language :: Python :: 3.9 Classifier: Programming Language :: Python :: 3.10 Classifier: Programming Language :: Python :: 3.11 Classifier: Programming Language :: Python :: 3.12 Classifier: Programming Language :: Python :: 3.13 Classifier: Programming Language :: Python :: Implementation :: CPython Classifier: Programming Language :: Python :: Implementation :: PyPy Classifier: Topic :: Software Development :: Libraries Classifier: Topic :: Utilities Requires-Python: >=3.9.0 Provides-Extra: colors Requires-Dist: colorama; extra == 'colors' Provides-Extra: plugins Requires-Dist: setuptools; extra == 'plugins' Description-Content-Type: text/markdown [![isort - isort your imports, so you don't have to.](https://raw.githubusercontent.com/pycqa/isort/main/art/logo_large.png)](https://pycqa.github.io/isort/) ------------------------------------------------------------------------ [![PyPI version](https://badge.fury.io/py/isort.svg)](https://badge.fury.io/py/isort) [![Test](https://github.com/PyCQA/isort/actions/workflows/test.yml/badge.svg)](https://github.com/PyCQA/isort/actions/workflows/test.yml) [![Lint](https://github.com/PyCQA/isort/actions/workflows/lint.yml/badge.svg)](https://github.com/PyCQA/isort/actions/workflows/lint.yml) [![Code coverage Status](https://codecov.io/gh/pycqa/isort/branch/main/graph/badge.svg)](https://codecov.io/gh/pycqa/isort) [![License](https://img.shields.io/github/license/mashape/apistatus.svg)](https://pypi.org/project/isort/) [![Join the chat at https://gitter.im/timothycrosley/isort](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/timothycrosley/isort?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) [![Downloads](https://pepy.tech/badge/isort)](https://pepy.tech/project/isort) [![Code style: black](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/psf/black) [![Imports: isort](https://img.shields.io/badge/%20imports-isort-%231674b1?style=flat&labelColor=ef8336)](https://pycqa.github.io/isort/) [![DeepSource](https://static.deepsource.io/deepsource-badge-light-mini.svg)](https://deepsource.io/gh/pycqa/isort/?ref=repository-badge) _________________ [Read Latest Documentation](https://pycqa.github.io/isort/) - [Browse GitHub Code Repository](https://github.com/pycqa/isort/) _________________ isort your imports, so you don't have to. isort is a Python utility / library to sort imports alphabetically and automatically separate into sections and by type. It provides a command line utility, Python library and [plugins for various editors](https://github.com/pycqa/isort/wiki/isort-Plugins) to quickly sort all your imports. It requires Python 3.9+ to run but supports formatting Python 2 code too. - [Try isort now from your browser!](https://pycqa.github.io/isort/docs/quick_start/0.-try.html) - [Using black? See the isort and black compatibility guide.](https://pycqa.github.io/isort/docs/configuration/black_compatibility.html) - [isort has official support for pre-commit!](https://pycqa.github.io/isort/docs/configuration/pre-commit.html) ![Example Usage](https://raw.github.com/pycqa/isort/main/example.gif) Before isort: ```python from my_lib import Object import os from my_lib import Object3 from my_lib import Object2 import sys from third_party import lib15, lib1, lib2, lib3, lib4, lib5, lib6, lib7, lib8, lib9, lib10, lib11, lib12, lib13, lib14 import sys from __future__ import absolute_import from third_party import lib3 print("Hey") print("yo") ``` After isort: ```python from __future__ import absolute_import import os import sys from third_party import (lib1, lib2, lib3, lib4, lib5, lib6, lib7, lib8, lib9, lib10, lib11, lib12, lib13, lib14, lib15) from my_lib import Object, Object2, Object3 print("Hey") print("yo") ``` ## Installing isort Installing isort is as simple as: ```bash pip install isort ``` ## Using isort **From the command line**: To run on specific files: ```bash isort mypythonfile.py mypythonfile2.py ``` To apply recursively: ```bash isort . ``` If [globstar](https://www.gnu.org/software/bash/manual/html_node/The-Shopt-Builtin.html) is enabled, `isort .` is equivalent to: ```bash isort **/*.py ``` To view proposed changes without applying them: ```bash isort mypythonfile.py --diff ``` Finally, to atomically run isort against a project, only applying changes if they don't introduce syntax errors: ```bash isort --atomic . ``` (Note: this is disabled by default, as it prevents isort from running against code written using a different version of Python.) **From within Python**: ```python import isort isort.file("pythonfile.py") ``` or: ```python import isort sorted_code = isort.code("import b\nimport a\n") ``` ## Installing isort's for your preferred text editor Several plugins have been written that enable to use isort from within a variety of text-editors. You can find a full list of them [on the isort wiki](https://github.com/pycqa/isort/wiki/isort-Plugins). Additionally, I will enthusiastically accept pull requests that include plugins for other text editors and add documentation for them as I am notified. ## Multi line output modes You will notice above the \"multi\_line\_output\" setting. This setting defines how from imports wrap when they extend past the line\_length limit and has [12 possible settings](https://pycqa.github.io/isort/docs/configuration/multi_line_output_modes.html). ## Indentation To change the how constant indents appear - simply change the indent property with the following accepted formats: - Number of spaces you would like. For example: 4 would cause standard 4 space indentation. - Tab - A verbatim string with quotes around it. For example: ```python " " ``` is equivalent to 4. For the import styles that use parentheses, you can control whether or not to include a trailing comma after the last import with the `include_trailing_comma` option (defaults to `False`). ## Intelligently Balanced Multi-line Imports As of isort 3.1.0 support for balanced multi-line imports has been added. With this enabled isort will dynamically change the import length to the one that produces the most balanced grid, while staying below the maximum import length defined. Example: ```python from __future__ import (absolute_import, division, print_function, unicode_literals) ``` Will be produced instead of: ```python from __future__ import (absolute_import, division, print_function, unicode_literals) ``` To enable this set `balanced_wrapping` to `True` in your config or pass the `-e` option into the command line utility. ## Custom Sections and Ordering isort provides configuration options to change almost every aspect of how imports are organized, ordered, or grouped together in sections. [Click here](https://pycqa.github.io/isort/docs/configuration/custom_sections_and_ordering.html) for an overview of all these options. ## Skip processing of imports (outside of configuration) To make isort ignore a single import simply add a comment at the end of the import line containing the text `isort:skip`: ```python import module # isort:skip ``` or: ```python from xyz import (abc, # isort:skip yo, hey) ``` To make isort skip an entire file simply add `isort:skip_file` to the module's doc string: ```python """ my_module.py Best module ever isort:skip_file """ import b import a ``` ## Adding or removing an import from multiple files isort can be ran or configured to add / remove imports automatically. [See a complete guide here.](https://pycqa.github.io/isort/docs/configuration/add_or_remove_imports.html) ## Using isort to verify code The `--check-only` option ------------------------- isort can also be used to verify that code is correctly formatted by running it with `-c`. Any files that contain incorrectly sorted and/or formatted imports will be outputted to `stderr`. ```bash isort **/*.py -c -v SUCCESS: /home/timothy/Projects/Open_Source/isort/isort_kate_plugin.py Everything Looks Good! ERROR: /home/timothy/Projects/Open_Source/isort/isort/isort.py Imports are incorrectly sorted. ``` One great place this can be used is with a pre-commit git hook, such as this one by \@acdha: This can help to ensure a certain level of code quality throughout a project. ## Git hook isort provides a hook function that can be integrated into your Git pre-commit script to check Python code before committing. [More info here.](https://pycqa.github.io/isort/docs/configuration/git_hook.html) ## Setuptools integration Upon installation, isort enables a `setuptools` command that checks Python files declared by your project. [More info here.](https://pycqa.github.io/isort/docs/configuration/setuptools_integration.html) ## Spread the word [![Imports: isort](https://img.shields.io/badge/%20imports-isort-%231674b1?style=flat&labelColor=ef8336)](https://pycqa.github.io/isort/) Place this badge at the top of your repository to let others know your project uses isort. For README.md: ```markdown [![Imports: isort](https://img.shields.io/badge/%20imports-isort-%231674b1?style=flat&labelColor=ef8336)](https://pycqa.github.io/isort/) ``` Or README.rst: ```rst .. image:: https://img.shields.io/badge/%20imports-isort-%231674b1?style=flat&labelColor=ef8336 :target: https://pycqa.github.io/isort/ ``` ## Security contact information To report a security vulnerability, please use the [Tidelift security contact](https://tidelift.com/security). Tidelift will coordinate the fix and disclosure. ## Why isort? isort simply stands for import sort. It was originally called "sortImports" however I got tired of typing the extra characters and came to the realization camelCase is not pythonic. I wrote isort because in an organization I used to work in the manager came in one day and decided all code must have alphabetically sorted imports. The code base was huge - and he meant for us to do it by hand. However, being a programmer - I\'m too lazy to spend 8 hours mindlessly performing a function, but not too lazy to spend 16 hours automating it. I was given permission to open source sortImports and here we are :) ------------------------------------------------------------------------ [Get professionally supported isort with the Tidelift Subscription](https://tidelift.com/subscription/pkg/pypi-isort?utm_source=pypi-isort&utm_medium=referral&utm_campaign=readme) Professional support for isort is available as part of the [Tidelift Subscription](https://tidelift.com/subscription/pkg/pypi-isort?utm_source=pypi-isort&utm_medium=referral&utm_campaign=readme). Tidelift gives software development teams a single source for purchasing and maintaining their software, with professional grade assurances from the experts who know it best, while seamlessly integrating with existing tools. ------------------------------------------------------------------------ Thanks and I hope you find isort useful! ~Timothy Crosley